@gitruck/cli 1.0.6 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -1,674 +1,678 @@
1
- # gtrk-cli (formerly the Tonghe Smart Creation Toolkit)
2
-
3
- **English** · [简体中文](README.md)
4
-
5
- <!-- Bilingual pair: edits here MUST be mirrored in README.md (section structure is guarded by test/readme-bilingual.test.mjs). -->
6
-
7
- > The video-production pipeline CLI for Gitruck Cloud (同合云) — **agents drive cloud jobs, artifacts land locally, and three editing-suite project formats (desktop client / Jianying / Premiere) stay interoperable**.
8
- >
9
- > One command turns a raw talking-head recording into an editable, re-cuttable project. The cloud does the heavy lifting, your machine only assembles, and the source video never leaves it.
10
-
11
- **🔗 [Website](https://cloud.ai-mcn.tv/zh-CN/cli) · [Tutorial](https://hocassian.feishu.cn/wiki/HCFpwoF7SivIFbkKosgcFMcEnxk) · [Quick start](https://cloud.ai-mcn.tv/zh-CN/docs/quick-start) · [Desktop client](https://cloud.ai-mcn.tv/zh-CN/download) · [npm](https://www.npmjs.com/package/@gitruck/cli) · [User agreement](https://hocassian.feishu.cn/wiki/T6UywR8b3ik4Mgk7tP9c1b7Kn0b) · [Privacy policy](https://hocassian.feishu.cn/wiki/ZLRNwlEhfishYtkosUhcofMYnPf)**
12
-
13
- ![Put AI creation capabilities into your local agent](assets/gtrk-agent-intro.png)
14
-
15
- ---
16
-
17
- ## Why gtrk-cli
18
-
19
- - **One command, three project formats**: upload the raw take → cloud-side smart editing (strips filler, repeats, long pauses) → pull back **desktop client (gtrk) + Jianying + Premiere/FCP** project files → the output folder opens automatically.
20
- - **Cloud does the heavy lifting, your machine only assembles**: recognition, cutting and alignment all happen in the cloud; locally you only receive the result, and **the source video never leaves your machine** (its path is written into the project, so opening it locally resolves the media directly).
21
- - **Built for agents**: ships with the `gtrk-oralcut` skill — inside Claude Code / Codex / Cursor / Gemini CLI / TRAE and friends, "cut this talking-head for me" is enough to kick it off. The CLI is the hands, the agent is the brain.
22
- - **A general-purpose toolbox**: a single binary with parallel subcommands — every `gtrk <xyz>` (oralcut / split / mg / matrix / render …) is a **domain-agnostic driver/tool**; a production flow starts whichever ones it needs and leaves the rest alone, and more drivers can be added later. Modelled on Feishu's (Lark) `lark-cli`. It is currently used for humanities & social-science videos, but nothing in the design is tied to any particular show.
23
-
24
- ## Features
25
-
26
- | | Command | What it does |
27
- |---|---|---|
28
- | 🎬 | `gtrk oralcut <raw>` | Full talking-head editing loop: emits gtrk + Jianying + Premiere projects in one pass and opens the output folder |
29
- | ✂️ | `gtrk long2short <raw>` | Long-to-short loop: semantic segment selection + jump cuts on a long video (optional 720p-proxy smart split-screen) → per-clip gtrk + Jianying + Premiere projects (the raw file is never uploaded). **If you only want a finished cut and will not edit further, use fine-cut** `gtrk tool video_long2short_pro` |
30
- | 📝 | `gtrk transcript <local video\|voice-over audio>` | Video/audio to transcript: the original file is not uploaded, only the locally extracted (or, for audio input, transcoded) 16 kHz audio derivative, producing one Markdown file with a summary, timecoded record and plain text; with `--json` it also emits a sentence-timecoded `transcript.json` (the input for the `gtrk project init` fallback path) |
31
- | 🎵 | `gtrk music-visualizer <audio>` | Music visualization: one song a spectrum-visualizer video (`--template` required, optional background/cover and template/color styling), with the companion driver skill `gtrk-music-visualizer` |
32
- | ✂️ | `gtrk split [split doc]` | Visual split dispatcher: finished cut × transcript projection validated beat storyboard (`struct_meta.split` + `dispatch.json`), driving four lanes; `--column <id>` validates against your show's vocabulary |
33
- | ⚙️ | `gtrk init` | Guided one-time setup (API key + Jianying draft folder), then forget about it |
34
- | 🩺 | `gtrk doctor` | Health check: config / cloud connectivity / Jianying folder / runtime in one shot |
35
- | 📦 | `gtrk deps` | Runtime assets: `status` shows where ffmpeg/fonts come from and under which licence, `install` fetches them from the Gitruck Cloud mirror (**must be triggered explicitly — never a silent auto-download**) |
36
- | 🤖 | `gtrk skills install` | Installs the 14 bundled CLI skills into the agents detected on this machine, via the generic `skills` adapter plus a gtrk supplement layer; `--all` covers every registered host |
37
- | ⬆️ | `gtrk upgrade` | Upgrade the CLI to the latest version + refresh skills (config preserved); `--check` only reports |
38
- | 🎞️ | `gtrk render` | Render a gtrk project (EDL) locally → finished mp4 (requires ffmpeg); output frames are allocated against the **cumulative** timeline (per-clip rounding never accumulates, so the picture cannot drift away from the voiceover); runs a QC pass afterwards and writes `.qc.json` (`--no-qc` skips it) |
39
- | 🔬 | `gtrk qc <cut>` | Final-cut QC: one decoding pass over the whole file for flash frames, black/frozen frames, clipping, silence and audio/video drift, each with a timecode; `--gtrk <project>` enables project-aware detection of **intra-clip cuts**, `--fail-on error\|warn\|never` gates pipelines via the exit code |
40
- | 🔎 | `gtrk matrix` | B-roll retrieval + **candidate track laying**: consumes the FILM_BROLL dispatch produces a candidate list + downloads preview proxies and lays N candidate tracks (`--lay N`, default 1; open it in opencut and toggle track visibility to compare; `--lay 0` produces the list only); `matrix search "<query>"` is a one-off ad-hoc search; `matrix fetch <clip_id...>` pulls raw footage during the fine cut (free re-signing + download for already-granted materials, drag straight into Jianying); **local-footage mode**: `matrix index --dirs <folders>` builds a slice-free index → `--local --dirs` retrieves and lays tracks (**your footage never leaves your machine**) → `matrix lay` consumes the (editable) plan; `matrix describe` understands candidates on demand |
41
- | 🎨 | `gtrk mg` | MG motion-graphics particle laying: consumes the MG dispatch → lays html-particle assets (transparent overlay / full-screen bed, produced by your show's MG skill) into the `.gtrk` `beat_track`; `mg lint <particle.html>` runs the statically checkable subset of the house rules, `mg status --project <dir>` is an orchestration dashboard; `mg render <particle.html> --duration <sec>` renders a single particle in the cloud, independent of any project, into a Jianying-readable qtrle transparent MOV (the fine-cut supplement channel); aux overlay particles can be layered on the same span (one beat derives a main particle plus `-aux<n>`). The old name `gtrk rrv` remains as a deprecated alias |
42
- | 🎙️ | `gtrk project init` | Audio-first project bootstrap: build a `.gtrk` project from a voice-over main path `--tts-task <task_id>` references a completed TTS task (fetches the audio plus sentence timecodes directly, zero ASR); fallback path `--audio`+`--transcript` takes your own voice-over as a pair. Once landed, `gtrk split --project` continues the production pipeline as usual |
43
- | 🎼 | `gtrk audio lay` | Audio-track atom: appends an audio track to a `.gtrk` project (BGM/score; idempotent same-source replacement, no track pile-up); `--beat-align` runs cloud beat analysis and snaps the in-point to the nearest downbeat (billed once; degrades gracefully without a key or on failure) |
44
- | 🎯 | `gtrk audio align` | Audio-video alignment part (fully local, zero billing): cross-correlates an external audio recording (lav mic / recorder) against the video to measure offset + confidence; high confidence swaps the track directly (video stream untouched byte-for-byte), low confidence emits an alignment project for the client timeline, then `--resume` reads the confirmed offset back; `--offset` swaps at an explicit offset |
45
- | 🧰 | `gtrk tool <name>` | Single-shot tool family: image-to-camera-move, image/video matting, image black-border removal / aspect adaptation / cleanup / square conversion / LivePhoto, smart collage covers and vertical stitching (multi-image input), video black-border removal / aspect adaptation / stabilization / vaporwave filter / mechanical & semantic shot segmentation / motion highlights / AI subtitles, vocal-accompaniment separation / speaker diarization / pitch-and-tempo shift, piano-to-MIDI and piano restoration, audio denoising, silence removal, MAD, and more; `gtrk tool list` shows every input/output/live price/status. Single request, single result, shared runner — adding a tool means adding one descriptor |
46
- | 💬 | `gtrk feedback` | Tell us what feels wrong: `gtrk feedback "<one line>" --command <command>`. **Disclosed submission** when an assistant files it for you it must first read the exact content back to you and only add `--disclosed` once you agree; in a pipe or any non-interactive environment, sending without that declaration is refused outright. Content is redacted before it leaves your machine (local paths, credentials, e-mail addresses, phone numbers and the like are replaced by shape), so what you are shown is exactly what gets sent |
47
- | 🚧 | `struct` | (planned) convert an existing gtrk project into the three formats |
48
-
49
- ---
50
-
51
- ## Getting an API key
52
-
53
- The CLI calls Gitruck Cloud capabilities, so you need an API key first (it looks like `gc_xxxxxxxx`):
54
-
55
- 1. Open **[cloud.ai-mcn.tv](https://cloud.ai-mcn.tv)** and sign in — **signing in activates your account**, free trial credits included, no gatekeeping.
56
- 2. Go to the **[console](https://cloud.ai-mcn.tv/zh-CN/dashboard)** and create/copy your key under "API keys / key management".
57
- 3. The next step, `gtrk install`, will prompt you to paste it (configure once, reuse locally forever).
58
-
59
- > Terms of record: [User agreement for the "OpenCut Gitruck Edition" client and the "gtrk CLI"](https://hocassian.feishu.cn/wiki/T6UywR8b3ik4Mgk7tP9c1b7Kn0b) · [Privacy policy](https://hocassian.feishu.cn/wiki/ZLRNwlEhfishYtkosUhcofMYnPf) — **signing in or completing registration on the website constitutes your acceptance**; when you call cloud capabilities from the CLI, you are the party primarily responsible for the legality of the content you process.
60
- >
61
- > Quick-start docs: [cloud.ai-mcn.tv/zh-CN/docs/quick-start](https://cloud.ai-mcn.tv/zh-CN/docs/quick-start) · Business enquiries: business@migotimes.com
62
-
63
- ## Install & first run
64
-
65
- Requires Node.js ≥ 20.6 (check with `node -v`).
66
-
67
- ```bash
68
- # 1) 一条命令装全:命令行 gtrk + /gtrk-oralcut skill + 配置(填 API Key、自动扫剪映目录)
69
- npm i -g @gitruck/cli@latest && gtrk install
70
- # 或免全局安装直接用:npx @gitruck/cli@latest install
71
-
72
- # 2) 剪一条(剪完自动打开产物目录)
73
- gtrk oralcut "D:/素材/某选题-原始口播.mp4" --script "D:/素材/某选题-文字稿.txt"
74
-
75
- # 或把本地视频转成一个 Markdown 文字稿
76
- gtrk transcript "D:/素材/采访视频.mp4"
77
- ```
78
-
79
- > Only want the config and not the skills? Use `gtrk init`. For local development: `cd gtrk-cli && bun install && bun run src/index.ts <command>`.
80
-
81
- The output folder is named `<raw-name>-video-project-<YYMMDD-HHMMSS>/` and contains the `gtrk/`, `jianying/` and `xml/` projects.
82
-
83
- > **Re-installing will not re-prompt for config**: `gtrk install` / `gtrk init` detect an existing setup and keep it, refreshing only the skills. Add `--reconfigure` to change things (you can press Enter to keep the existing key or Jianying folder).
84
-
85
- ## Operating map: from zero to a finished video
86
-
87
- > **You just talk; let the agent do the CLI typing.** Below is the end-to-end route — what comes first, what comes next, and what to do when things go sideways.
88
-
89
- **One-time setup (once, then forget)**
90
-
91
- 1. **Install the CLI**: `npm i -g @gitruck/cli@latest && gtrk install` (installs gtrk + skills + your API key in one go).
92
- 2. **(Optional) Create a show style**: if you want your own visual grammar and vocabulary, tell your agent "**build the style system for my show**" (`/gtrk-style-maker` interviews you and turns the answers into your own skill family plus a show config). **Skip it and you get the default kitchen** — the end-to-end flow still runs.
93
-
94
- **Per video (an ordered SOP with checkpoints — you talk to the agent, and it is not a one-shot parallel fan-out)**
95
-
96
- Lanes are laid **in order, with a checkpoint at every step**: first fill the B-roll base layer from all three sources (film footage / your local footage / AI scene clips) → you adjust it → sample frames to check the final composition → only then stack MG (incl. ov) on top. You drive each step by conversation and the agent runs the matching command.
97
-
98
- **Three entry chains, one merge point.** What your material looks like decides which chain you take; once you hold a project plus its transcript, all three are identical:
99
-
100
- ```
101
- ① 口播链 你对着镜头讲的一条口播 gtrk oralcut
102
- 短视频口播 / 人文社科杂谈 照稿剪掉重来·口误·长停顿
103
-
104
- ② 配音链 你写的一段稿子 → AI 配音 gtrk project init
105
- 电影解说 / 美食解说 先把配音调舒服,再建工程
106
-
107
- ③ 长剪短 一条几十分钟的长素材 gtrk long2short
108
- 播客·圆桌·脱口秀·访谈·直播回放 挑出值得单发的,逐条出工程
109
-
110
- ══════════ 工程 + 文稿 ══════════ ← 汇合点:往下三条链一样
111
-
112
- ┌───────────────────────┴───────────────────────┐
113
- │ │
114
- 配画面(可选,次序不能跳) 只想快点出片
115
- │ │
116
- gtrk split 把文稿分段派活
117
-
118
- gtrk matrix 按文稿铺 B-roll
119
-
120
- AI 再现(可选) 外部平台出片 → 手动回铺
121
-
122
- 客户端挑选 抽帧核构图 ← 底轨定稿前别往下走
123
-
124
- gtrk mg MG 主颗粒 + OV 叠层,最后才叠
125
-
126
- gtrk audio lay 全片加 BGM(可选)
127
-
128
- └───────────────────────┬───────────────────────┘
129
-
130
- 客户端:上字幕 → 出片
131
- (或导出剪映草稿 / PR 工程)
132
- ```
133
-
134
- Chain names above: *口播链* = talking-head (you shot yourself: short-form monologue, humanities commentary) · *配音链* = voice-over (you wrote a script: film recaps, food recaps) · *长剪短* = long-to-short (podcasts, roundtables, stand-up, interviews, stream VODs).
135
-
136
- **Two things to remember**: (1) **lay the bottom first, stack the top last** — B-roll and AI scene clips are both base-layer picture (two legs of one stage), while motion graphics (MG main particles + OV transparent overlays) are the only overlay layer, so stacking before the base is final is wasted work; (2) the final render always happens in the desktop client or your own NLE — the CLI only fills the project.
137
-
138
- > Full walkthroughs for each chain (artifacts per step, troubleshooting) live in the tutorial's sub-pages.
139
-
140
- | Step | What you say to the agent | What the agent does | Where you step in |
141
- |:--:|---|---|---|
142
- | ① | "**cut a version** of this talking-head" | `/gtrk-oralcut` → `gtrk oralcut` → three projects + transcript | — |
143
- | | "now **split it into a storyboard dispatch**" | `/gtrk-splitter` → `gtrk split` → `dispatch.json` with four lanes | review the dispatch |
144
- | | "**lay the B-roll base**" (two legs, one stage) | `/gtrk-matrix` → `gtrk matrix` → film/local-footage candidate tracks laid; `/gtrk-ai-drama` (skill, no command) → four-part description docs (Chinese/English blocks) | **pick/adjust B-roll in opencut** (toggle track visibility to compare); generate AI clips on an external platform and **drop them back in by hand** |
145
- | | "B-roll is settled, **check the composition**" | samples frames from the **merged three-source base layer** (an agent discipline, no dedicated command) | **confirm the composition** (subject position / safe areas / facing / brightness) |
146
- | | "composition looks good, **lay the MG**" | `/gtrk-mg` `gtrk mg` MG (incl. ov) stacked on the settled base layer | fine-tune particles (by hand in opencut) |
147
- | | "**produce the final cut**" | the desktop client's production chain (multi-lane compositing + cloud particle rendering / export to Jianying); `gtrk render` only produces a **main-track snapshot preview** | final polish inside the client |
148
-
149
- > The order exists for a reason: **AI scene clips belong to the base-layer B-roll family, not to an overlay layer** — the only overlay layer in the pipeline is MG (incl. ov). MG placement shapes itself around the picture and **depends on the final composition of the base layer**, so all three sources (film / local / AI) must land and the composition must be checked before MG goes on. Skip lanes you do not need (an empty queue in `dispatch` simply lays nothing).
150
- >
151
- > ⚠️ **Older docs said "④ lay MG → ⑤ AI re-enactment last", reasoning "the later it comes, the higher it stacks" — that mistook work order for layer order, corrected on 2026-08-17.** If your installed skills predate this, run `gtrk upgrade` to pick up the new order.
152
- >
153
- > **AI generation is asynchronous**: external platforms can take days of rerolls, and strict serialization would block ④⑤ indefinitely. The gate into ⑤ is therefore "**AI clips are back in ∨ you explicitly say skip for now**"; when you skip, the agent marks the MG particles adjacent to or overlapping the AI spans as "recheck composition once AI clips land" and repeats that list at wrap-up.
154
- >
155
- > ③④⑤⑥ all require **going back to the desktop client** to select, polish, re-insert and produce — the CLI lays material into `.gtrk`, and the client turns `.gtrk` into a finished video. See the "**CLI × desktop client**" section below.
156
-
157
- **When things go sideways**
158
-
159
- | Situation | What to do (tell the agent, or it handles it) |
160
- |---|---|
161
- | You only want the editing project, no visuals yet | Stop after "cut a version": "just the editing project for now" |
162
- | Lost the report / want the artifacts on another machine | "fetch the previous one by taskId" `gtrk oralcut-result <taskId>` (skips the cloud re-run) |
163
- | You want to choose between several B-roll candidates | "lay a few more B-roll candidates" → `gtrk matrix --lay N`, then toggle track visibility in opencut |
164
- | B-roll fill is poor / there are empty slots | Adjust `--score-floor` / `--top-k` and re-run, or "search a single query" → `matrix search "<query>"` to patch it |
165
- | You want to lay B-roll from your own footage | "use my local footage" `gtrk matrix index --dirs <folders>` to build the index, then `gtrk matrix --local --dirs --project …` (**your footage never leaves your machine**; see the matrix section in the command reference) |
166
- | Picture / particles need frame-level polish | Open the project in opencut and adjust by hand (what the agent laid is an **editable project**, not a flattened render) |
167
- | Cannot connect / config problems | "run a health check" `gtrk doctor` (config / cloud / Jianying folder / version in one shot) |
168
- | A new version is out | "upgrade" → `gtrk upgrade` (upgrades the CLI + refreshes skills, config preserved) |
169
-
170
- ## CLI × desktop client: hands and brain, one `.gtrk` throughout
171
-
172
- **The standard workflow is never "CLI only" — it is the CLI and the desktop client working together, and the client is an unavoidable part of producing a finished video.** The division of labour:
173
-
174
- - **CLI = headless assembler (hands / mechanical work)**: it deterministically packs cloud editing results, retrieved B-roll and show-produced particles into the project and atomically writes back `.gtrk` (cut the talking-head / split the dispatch / lay B-roll candidate tracks / lay MG particles). It makes no aesthetic judgements and produces no final cut.
175
- - **Desktop client = the workbench with a screen (eyes / polish)**: it opens **the same `.gtrk`** so you can look, choose, polish frame by frame, drop AI clips back in, and produce the final video. Installation is the one-liner in the "Upgrade desktop client" section (OpenCut Gitruck Edition).
176
-
177
- **`.gtrk` is the handover medium between them** — it is Gitruck Cloud's unified project contract (a true superset of a timeline + HTML particles + `struct_meta`), **written by the CLI, read by the client, in both directions**. So a video advances by **alternating** between CLI and client:
178
-
179
- ```
180
- CLI 写 .gtrk ─▶ 客户端打开(自动感知外部改动、先存脏改再刷新、不丢稿)
181
- ─▶ 你在客户端挑/调/精修 ─▶ 需要就再喊 agent 让 CLI 写下一轮(铺 MG / 铺 AI…)
182
- ─▶ 反复 ─▶ 客户端出片
183
- ```
184
-
185
- **These things can only be done in the client (the CLI cannot give them to you):**
186
-
187
- | Stage | Why it must happen in the client |
188
- |---|---|
189
- | **Choosing B-roll candidates** | `gtrk matrix` lays N candidate tracks; you toggle each track's visibility to compare, pick one, and delete the rest — an aesthetic call only a person in the client can make |
190
- | **MG / particle polish** | The client renders html-particles as **live transparent previews** with frame-level Transform/Blending/Effects tuning |
191
- | **Talking-head fine cut** | Magnetic main-track ripple editing, manual nudging of cut points / pauses / split-screens |
192
- | **Re-inserting AI re-enactment** | AI clips generated on external platforms are **dragged into the AI_DRAMA lane by hand** and aligned to their spans (`/gtrk-ai-drama` only emits description docs; the footage is produced externally see SOP ③: it belongs to the base-layer stage, and MG waits until it has landed) |
193
- | **Final production** | Multi-lane compositing (overlay / MG / cloud-rendered particles stacked) plus Jianying draft export both live in the client's production chain |
194
-
195
- > **`gtrk render` ≠ the final cut.** `gtrk render` is a local ffmpeg **snapshot preview of the main track (the rough talking-head cut)** — it merges only the main video and audio tracks and **does not composite overlays (B-roll candidates) / MG particles / AI re-enactment**. For a **real multi-lane finished video** (all lanes stacked, particles cloud-rendered, Jianying draft exported), use the **client's production chain**. In one line: **the CLI puts material into the project; the client turns the project into a video.**
196
-
197
- ## Upgrading
198
-
199
- **CLI + skills** (config preserved as-is):
200
-
201
- ```bash
202
- gtrk upgrade # 有新版则升到最新 + 刷新 skill
203
- gtrk upgrade --check # 只看有没有新版,不动手
204
- ```
205
-
206
- > If you use `npx` (no global install), you already get the latest every time: `npx @gitruck/cli@latest install`. `gtrk doctor` will also mention when a newer version exists.
207
-
208
- **Desktop client**: re-run the one-line installer to overwrite-install the latest (per-user, no admin rights, config untouched):
209
-
210
- ```powershell
211
- irm https://api.ai-mcn.tv:9000/broadcast/exe/install.ps1 | iex
212
- ```
213
-
214
- ## Using it with AI agents
215
-
216
- Once installed, a single sentence in any agent invokes a gtrk skill:
217
-
218
- | | |
219
- |:--:|:--:|
220
- | ![Calling gtrk from an agent, example 1](assets/agent-example-1.png) | ![Calling gtrk from an agent, example 2](assets/agent-example-2.png) |
221
- | ![Calling gtrk from an agent, example 3](assets/agent-example-3.png) | ![Calling gtrk from an agent, example 4](assets/agent-example-4.png) |
222
-
223
- `gtrk install` installs the 14 bundled CLI skills (`gtrk-oralcut`·`gtrk-long2short`·`gtrk-splitter`·`gtrk-matrix`·`gtrk-mg`·`gtrk-ai-drama`·`gtrk-style-maker`·`gtrk-transcript`·`gtrk-tools`·`gtrk-music-visualizer`·`gtrk-cover`·`gtrk-travel-recap`·`gtrk-live-slicing`·`gtrk-talking-head`) into the agents detected on this machine. The mechanism matches lark-cli: gtrk hands its local skill sources to the generic `skills` CLI, which owns agent detection, directory mapping and update rules; gtrk no longer hardcodes per-vendor paths.
224
-
225
- By default `~/.agents/skills` is the single source of truth, linked into each agent's compatible directory (junctions on Windows); where linking is unavailable the adapter falls back to copying. That way updates touch one canonical copy instead of letting duplicates drift apart. Common commands:
226
-
227
- ```bash
228
- # 自动探测已安装的 Agent(等价核心:npx -y skills add <gtrk包根>/skills -g -y)
229
- gtrk skills install
230
-
231
- # 只装指定宿主;这里使用通用 skills CLI 的 Agent ID
232
- gtrk skills install --agents codex,cursor,gemini-cli,trae-cn
233
-
234
- # 安装到适配器当前支持的全部 Agent(会创建较多宿主目录)
235
- gtrk skills install --all
236
-
237
- # 不使用链接,每个宿主各复制一份
238
- gtrk skills install --copy
239
- ```
240
-
241
- `--agents` accepts agent IDs from both the upstream adapter and the gtrk supplement layer. Chinese agents already covered include `trae`, `trae-cn`, `codebuddy`, `qoder`, `qoder-cn`, `qwen-code`, `kimi-code-cli`, `iflow-cli`, `codearts-agent` and `lingma`, plus `workbuddy`, `qoderwork` and `comate` which upstream has not registered yet. Common shorthands — `qwen`, `kimi`, `iflow`, `codearts`, `tongyi-lingma`, `qoder-work`, `baidu-comate` — are mapped automatically. When upstream adds new agents, gtrk can use the new IDs without a release; if an existing script must hardcode a directory, `--dir <skills dir>` still gives you the compatible copy mode.
242
-
243
- **Agent input UIs are not standardized**: Claude usually surfaces skill names in `/` completion; different Codex clients enter via `$`, `/skills` or a Skills panel; TRAE relies mostly on Skills settings, explicit naming or semantic triggering. So not seeing a Claude-style `/gtrk-*` dropdown does not mean the skill is missing. If a new skill does not show up, refresh the window or start a new session.
244
-
245
- Then just say "**cut a version of this talking-head**", or explicitly pick `gtrk-oralcut` from your agent's Skills entry point. The agent will ask about the raw file, script and pacing, call `gtrk oralcut --json` to run the loop, verify the artifacts and tell you how to open all three formats. The full portable playbook is in [`AGENT.md`](./AGENT.md).
246
-
247
- **Hand the whole chain to the agent**: it is not just the talking-head cut — keep going with "split the storyboard", "lay the B-roll", "lay the MG particles", "render the video", and the agent will pair each show-specific production skill with `gtrk split` / `gtrk matrix` / `gtrk mg` / `gtrk render` to run the entire **production pipeline**. **You just talk; leave the CLI typing to the agent** — the "Command reference" below exists so the agent can look up parameters, not so you type them in a terminal.
248
-
249
- ### Capabilities agents can drive (skill drives command)
250
-
251
- **Each capability = one skill (the brain — you trigger it, it knows its place in the SOP and handles interaction) driving one gtrk command (the hands — deterministic mechanical work).** Production is an **ordered SOP with a user checkpoint at every step**, not a one-shot parallel fan-out — a `/gtrk-X` skill runs `gtrk X` at the right moment, with your confirmation:
252
-
253
- | SOP | Driving skill (what you say) | Underlying command (what the agent runs) | What it does |
254
- |:--:|---|---|---|
255
- | ① | `/gtrk-oralcut` | `gtrk oralcut` | Smart talking-head cut → desktop client / Jianying / Premiere projects + transcript |
256
- | | `/gtrk-splitter` | `gtrk split` | Storyboard dispatch`dispatch.json` (A_ROLL/MG/AI_DRAMA/FILM_BROLL, four lanes) |
257
- | | `/gtrk-matrix` | `gtrk matrix` | **B-roll base · film/local-footage leg**: lays candidate tracks **you adjust/choose** (toggle visibility in opencut) |
258
- | ③ | `/gtrk-ai-drama` | (no command, pure authoring) | **B-roll base · AI scene-clip leg (same stage as matrix, not last)**: emits four-part description docs (backstory / characters / shots / source text, in Chinese and English blocks) → generate on any external platform and re-insert by hand (the artifact is description text with no mechanical tail, same as `/gtrk-style-maker`: skill only, no command) |
259
- | | (no skill) | (no command) | **Global frame-sampling composition check**: sample frames from the merged three-source base layer and have the user confirm the composition a hard agent-discipline gate feeding ⑤'s placement decisions |
260
- | | `/gtrk-mg` | `gtrk mg` | **MG (incl. ov) goes on last** (stacked on the settled, composition-checked base layer) |
261
- | | `/gtrk-style-maker` | (no command, builds a show) | A one-time interview that builds your show's style system (skill family + show config, see next section) |
262
- | — | (wrap-up) | `gtrk render` | Render a gtrk project locally finished mp4 |
263
- | ✂️ | `/gtrk-long2short` | `gtrk long2short` | Long-to-short rough cut: semantic segment selection + jump cuts per-clip client/Jianying/Premiere projects (the raw file is never uploaded); **not part of the production SOP**, usable standalone at any time |
264
- | 📝 | `/gtrk-transcript` | `gtrk transcript` | Local video / voice-over audio one Markdown file with an agent-written summary, timecoded record and plain text; **not part of the production SOP** |
265
- | 🧰 | `/gtrk-tools` | `gtrk tool <name>` | The single-shot tool family (image-to-camera-move / image & video matting …) single request, single result, **not part of the production SOP**, usable standalone at any time |
266
- | 🎵 | `/gtrk-music-visualizer` | `gtrk music-visualizer` | One song a spectrum-visualizer video (template + optional background/cover + colour styling), **not part of the production SOP**, used standalone for audience acquisition |
267
- | 🖼️ | `/gtrk-cover` | (no command, pure authoring) | The two-stage cover workbench: design diagnosis + text-to-image prompts in three sizes and two languages → you generate images on an external platform → an HTML5 typesetting workbench (drag/scroll fine-tuning, one-click export to multiple PNG sizes). Show-specific cover aesthetics are injected through the show config's `style.skills` (`produces:"cover"`); **not part of the production SOP** (it is the "stage zero" companion to distribution) |
268
-
269
- > **Skill vs command**: `/gtrk-mg` is the **brain** — it knows it belongs at SOP step ⑤ (MG only after all three B-roll sources have landed and the composition is checked), asks for your confirmation, and resolves which particle type to produce from the show config; `gtrk mg` is the **hands** — purely deterministic lint + track laying. You trigger the skill by talking, and the skill runs the command for you.
270
- > The 12 `/gtrk-X` skills above are **framework skills bundled with the CLI** (installed by `gtrk skills install`) `/gtrk-long2short` independently drives long-to-short, `/gtrk-transcript` independently drives video/audio-to-transcript, `/gtrk-tools` covers only the single-shot tool family, `/gtrk-cover` handles covers, and none of the four belong to the production SOP; `/gtrk-ai-drama`·`/gtrk-style-maker`·`/gtrk-cover` are pure authoring skills (no command). Show-specific **visual style and content** come instead from your own show's production skills (created by `/gtrk-style-maker`, bound through the show config's `style.skills`) and are never hardcoded into these framework skills.
271
-
272
- **How each lane's actual visuals/content get produced** — what the MG looks like, what tone the AI re-enactment has — is not hardcoded into the CLI. It comes from **your own show's production skills** (created interactively with `/gtrk-style-maker`, kept locally). They are bound through the show config's **`style.skills[].produces`** (the value is the lane name), and **general-purpose drivers** such as `gtrk mg` / `gtrk matrix` consume them accordingly. **The direction is: the CLI drives the show skills** — show skills only supply style/content and carry no "which command to run" orchestration; the framework only knows lanes and pipeline interfaces, and the look always belongs to your show. Without a show, the built-in defaults are used and everything still runs end to end.
273
-
274
- ---
275
-
276
- ## Shows and style: a two-layer structure
277
-
278
- > **The show config is remodelling your kitchen; producing a video is cooking dinner. You do not remodel the kitchen before every dish, but every dish is indeed cooked in the kitchen you remodelled.**
279
-
280
- The system has two layers on completely different time scales:
281
-
282
- **[Show layer · one-time / infrequent] = building a show (remodelling the kitchen)**
283
- Run `/gtrk-style-maker` (a meta skill). It uses a heuristic interview to help you work out **your own** visual grammar presupposing no dimensions at all: it does not assume you have a narrative structure, a thematic system, or a split between animation and live action. Your dimensions and their values are entirely yours to define. It produces:
284
-
285
- - Your own executable skill family (written into the current agent's user-level skills directory; a black box, kept local)
286
- - A vocabulary shared inside the show (referenced by every skill in the family, preventing drift between multiple definitions)
287
- - The show config `~/.gitruck/columns/<id>.json` (vocabulary + B-roll retrieval preferences + a list of style references)
288
-
289
- **[Production layer · every video] = cooking (the shape of the flow never changes)**
290
- Cut the talking-head split the script → dispatch (B-roll retrieval / motion graphics / re-enactment) → assemble → render. Every step explicitly consumes the current show config: script splitting validates against your vocabulary (`--column <id>` or the config's `defaultColumn`), B-roll retrieval follows your show's retrieval preferences (`broll.column_tag_ids` show tags / `material_class_policy` / facets), and each lane goes through your own production skills.
291
-
292
- **No show configured? Use the default "kitchen".** Zero config = the built-in default show; everything runs end to end, byte-for-byte identical to the behaviour before show configs existed — the show layer is an optional asset, not a mandatory gate.
293
-
294
- **Pipeline contract**: the framework presupposes nothing about aesthetics and is fully authoritative about pipeline interfaces. Skills whose artifacts enter the render pipeline must satisfy the corresponding contract (see [`contracts/`](./contracts/README.md), e.g. `gsap-emit v1` for HTML animation particles); a contract only constrains machine-decidable pipeline properties, and what the picture looks like is always yours.
295
-
296
- ---
297
-
298
- ## Configuration
299
-
300
- `gtrk init` writes config to `~/.gitruck/config.json` (a unified user-level directory — config, caches, ffmpeg and show configs all live under `~/.gitruck/`). Resolution order: **environment variables / `.env` > persisted `init` config > default base URL**.
301
-
302
- | Item | Source | Notes |
303
- |---|---|---|
304
- | `GITRUCK_API_KEY` | env / init | The **bare value** of the `Authorization` header (not a Bearer token) |
305
- | `GITRUCK_API_BASE` | env / init | API base URL, defaults to `https://api.ai-mcn.tv:10000` |
306
- | Jianying draft folder | init / auto-detect / `--jianying-draft-dir` | Determines where Jianying drafts land and whether they open directly |
307
- | `defaultColumn` | hand-written in config.json | Default show config id (used by `gtrk split` when `--column` is omitted; if that is also missing, the built-in default show) |
308
- | Show config | `~/.gitruck/columns/<id>.json` | One file per show; generated and registered by `/gtrk-style-maker`, or hand-written |
309
-
310
- Non-interactive configuration (scripts / CI):
311
-
312
- ```bash
313
- gtrk init --api-key <KEY> --jianying-draft-dir auto -y
314
- ```
315
-
316
- Run `gtrk doctor` any time for a self-check:
317
-
318
- ```
319
- ✅ 运行时:node v24.x
320
- CLI 版本:v0.3.0(已是最新)
321
- API Key:已配(gc_xxx…)
322
- 云端连通 + 鉴权:可达,鉴权通过
323
- 剪映草稿目录:C:\Users\…\com.lveditor.draft
324
- ```
325
-
326
- ---
327
-
328
- ## Command reference
329
-
330
- ### `gtrk transcript <local video|voice-over audio>`
331
-
332
- Turns a local video or voice-over audio file into a multi-level Markdown transcript. It accepts local file paths only: video is extracted — and audio input transcoded — to 16 kHz mono audio on your machine, and only that derivative is uploaded. The original file is never uploaded, and URLs or platform video downloads are not supported.
333
-
334
- ```bash
335
- gtrk transcript "D:/素材/采访视频.mp4"
336
- gtrk transcript "D:/素材/采访视频.mp4" --lang zh-CN --out "D:/文字稿/采访.md" --json
337
- ```
338
-
339
- By default it produces only `D:/素材/采访视频-transcript.md`, whose structure is fixed:
340
-
341
- 1. `## 总结` (Summary): the CLI marks it as pending, and `/gtrk-transcript` drives the agent to read the full text, generate it and write it back;
342
- 2. `## 文字记录` (Transcript record): readable paragraphs each starting with `[00:01:23]`;
343
- 3. `## 纯文本` (Plain text): the complete recognized text, easy to copy in one go.
344
-
345
- Live pricing is queried from the website's price table under `asr` before the run; neither the CLI nor the docs store price numbers. With `--json`, stdout contains only `{ok,taskId,fileId,output,transcriptJson,summaryPending}`, where `output` points at that single Markdown file; `summaryPending:true` means `/gtrk-transcript` still needs the agent to write the semantic summary and replace the pending marker in place — the deliverable remains the same single file.
346
-
347
- > With `--json` it additionally drops a sentence-timecoded `<name>-transcript.json` next to the source file (`utterances[]{id,text,st,ed}` + `material_id` + `text_hash` + `duration`, field-for-field aligned with the transcript structure `gtrk split` consumes), which the `gtrk project init --transcript` fallback path can consume directly. **Do not re-run ASR here on TTS-synthesized voice-overs** — `gtrk project init --tts-task` fetches the server-side sentence timecodes directly, zero ASR and zero extra billing.
348
-
349
- ### `gtrk oralcut <raw>`
350
-
351
- | Parameter | Purpose | Default |
352
- |---|---|---|
353
- | `-s, --script <file>` | Script txt (cutting against a script is more accurate) | Looks for a `.txt` next to the raw file; otherwise reconstructs the script automatically |
354
- | `-p, --preset <p>` | Pacing `steady`\|`concise`\|`compact` (loose tight) | `concise` |
355
- | `-o, --out <dir>` | Custom output folder | `<raw-name>-video-project-<timestamp>` |
356
- | `-f, --formats <list>` | Comma-separated list of the three formats | `gtrk,jianying,xml` |
357
- | `--jianying-draft-dir <dir>` | Jianying draft root (or `auto`) | Reads the init config / auto-detects |
358
- | `--reupload` | Force re-upload, ignoring the upload cache | off |
359
- | `--no-open` | Do not open the output folder when done | **opens automatically by default** |
360
- | `--json` | Machine-readable: stdout carries only the result JSON (for agents / scripts) | off |
361
-
362
- `--json` output (a single stdout line on success): `{ ok, outDir, files:{gtrk,jianying,xml}, jianyingDraftPath, rendered, report, errors, taskId, fileId }`; on failure the process exits non-zero, errors go to stderr, and stdout carries no JSON.
363
-
364
- > Every run **always writes a `result.json` into the output folder** (regardless of `--json`), and once submission succeeds it also drops a `task.json` breadcrumb. Even if stdout is lost or the run crashes midway, the report and `taskId` are on disk, and `oralcut-result` below can fetch everything back in seconds without re-running the cloud job.
365
-
366
- ### `gtrk oralcut-result <taskId>`
367
-
368
- Fetches the report and the three project formats of an **already completed** task by `task_id` (with optional local rendering), **skipping preprocessing / upload / submission / polling** — use it when the report is lost or you want to pull the artifacts again on another machine, without re-running the cloud job.
369
-
370
- | Parameter | Purpose | Default |
371
- |---|---|---|
372
- | `-o, --out <dir>` | Output folder | `<cwd>/<taskId>-video-project-<timestamp>` |
373
- | `--render` | Additionally render locally (requires the raw file still at the path embedded in gtrk, plus ffmpeg) | off |
374
- | `--jianying-draft-dir <dir>` | Jianying draft root (or `auto`) | Reads the init config / auto-detects |
375
- | `--no-open` / `--json` | Same as `oralcut` | |
376
-
377
- > Fetching results requires the **same account's** API key that submitted the task (a different account or a deleted task returns `TASK_NOT_FOUND`). The report is stored with the task record and stays available long-term; the underlying artifact files are cleaned up after roughly **60 days**, after which the report is still retrievable but artifact downloads 404 (the command tells you and still writes the report to disk).
378
-
379
- ### `gtrk split [split doc]` — visual split dispatcher
380
-
381
- Finished cut × transcript projection → beat storyboard. **No positional argument = export the projection view** (projects the current `.gtrk` timeline × transcript into a beat view for splitting/proofreading, without writing back); **with a split doc = validate and land it** (validates the doc's machine contract → projects beat timecodes → atomically writes back `struct_meta.split` and produces the `split/dispatch.json` dispatch list, driving the A_ROLL / MG / AI_DRAMA / FILM_BROLL lanes). Timecodes always belong to the CLI (a split doc only describes "which span does what" and never carries timecodes).
382
-
383
- | Parameter | Purpose | Default |
384
- |---|---|---|
385
- | `--project <dir>` | The oralcut output folder (locates `gtrk/project.gtrk` and `transcript/transcript.json` automatically) | — |
386
- | `--gtrk <path>` / `--transcript <path>` | Explicit project / transcript paths (fallback for non-standard layouts) | Derived from `--project` |
387
- | `--column <id>` | Show config id (validates lane / category / produces against your show's vocabulary) | config `defaultColumn` → built-in default show |
388
- | `--md` | Also render the human-readable `split/visual-split.md` when landing (rendered one-way from the JSON) | off |
389
- | `--words` | Attach word-level detail in view mode | sentence level only |
390
- | `--json` | Machine-readable: stdout carries only the result JSON | off |
391
-
392
- > The landed `dispatch.json` has three queues feeding downstream consumers: `mg` (MG particles) → the `gtrk mg` command, `film_broll` → the `gtrk matrix` command, `ai_drama` → the `/gtrk-ai-drama` skill (which emits four-part description docs in Chinese/English blocks; pure authoring, no command). The companion skill `/gtrk-splitter` produces the split doc.
393
- >
394
- > **Dispatch entries carry their own `span:{from,to}`** (the utterance range that entry covers; `overlay` aux entries carry **their own** span, which may be a sub-range of the main beat's). **`track_st/track_ed` are a snapshot taken at projection time** — `gtrk mg` / `gtrk matrix` **re-project on the spot** when consuming them (see below), so after editing the talking-head track you do **not** need to re-run `gtrk split`; only a change to the split doc itself requires that.
395
-
396
- ### `gtrk patch <move|trim|split|set>` — element-level editing (the only way to edit a project)
397
-
398
- Edit the timecode or parameters of a single clip / gap / particle. **Agents must not hand-edit `.gtrk` JSON** —
399
- a clip carries **two parallel timecode representations** (`clip_st`+`clip_ed` and `clip_st`+`duration`).
400
- Changing one without the other is a **silent failure**: the desktop client reads `clip_ed` first while the
401
- backend does not strictly validate it, so nothing errors out yet the render uses a stale out-point.
402
- This command handles identity synchronisation + frame alignment + a whole-file check before writing.
403
-
404
- ```bash
405
- gtrk patch move --project <dir> --clip c2 --to 5.0
406
- gtrk patch trim --project <dir> --clip c2 --out -1s
407
- gtrk patch split --project <dir> --clip c2 --cut 5.5
408
- gtrk patch set --project <dir> --track audio:1 --at 3.0 --volume 0.5
409
- ```
410
-
411
- | Flag | Purpose | Default |
412
- |---|---|---|
413
- | `--project <dir>` / `--gtrk <path>` | Project dir (auto-locates `gtrk/project.gtrk`) or an explicit path | — |
414
- | `--clip <clip_id>` | Address by id. A video/audio **mirror pair** counts as one editing unit | — |
415
- | `--track <kind:idx> --at <sec>` | Address by position (`track_st at < track_ed`). Mutually exclusive with `--clip` | — |
416
- | `--to <sec\|Nf>` | Target position for `move` | — |
417
- | `--in` / `--out` / `--set-in` / `--set-out` / `--slip` | The five `trim` semantics (first two relative, next two absolute, `--slip` shifts only the source window) | — |
418
- | `--cut <sec\|Nf>` | Cut point for `split`. ⚠️ Distinct from the addressing flag `--at` | — |
419
- | `--muted` / `--volume <gain>` / `--opaque` | Element-level parameters for `set` (`--volume` is linear gain, not dB) | — |
420
- | `--total <sec\|Nf\|max>` | Top-level duration for `set` (project-scoped op, mutually exclusive with element addressing) | — |
421
- | `--ops <file\|->` | Batch transaction: read once, compute all, validate all, write once; any failure writes **nothing** | off |
422
- | `--dry-run` | Compute and validate only, do not write | off |
423
- | `--json` | Machine-readable receipt on stdout (human logs go to stderr) | off |
424
-
425
- > Time literals: seconds (`3.5` / `3.5s`) or frames (`105f`); relative values take a sign (`-1s`).
426
- >
427
- > The receipt carries `ops[].resolved`, a locator triple `{track, clip_id, track_st}` — use it on the next
428
- > round to confirm you are still pointing at the same element.
429
- > `preexisting[]` lists invariant problems that were **already in the file** (not caused by this run, not
430
- > blocking); violations caused by this run mean **zero writes and a non-zero exit**.
431
- >
432
- > ⚠️ A gap cannot be addressed with `--clip ""`: the contract lets multiple gaps share that value, so it is
433
- > not an address. Use `--track/--at` instead.
434
-
435
- ### `gtrk matrix` — B-roll retrieval + candidate track laying
436
-
437
- **No positional argument = consume the dispatch**: reads the `film_broll` queue from `split/dispatch.json` → dual-endpoint retrieval → produces the candidate list `split/broll-plan.json`, downloads preview proxies, and lays N candidate tracks in the project (open it in opencut and toggle track visibility to compare and choose). **`matrix search "<query>"` = a one-off ad-hoc search** (independent of any dispatch). **`matrix fetch <clip_id...>` = pull raw footage during the fine cut** (project-independent; see below).
438
-
439
- | Parameter | Purpose | Default |
440
- |---|---|---|
441
- | `--project <dir>` | The oralcut output folder (locates `split/dispatch.json` and the artifact destination) | — |
442
- | `--dispatch <path>` | Explicit `dispatch.json` path | Derived from `--project` |
443
- | `--column <id>` | Show config id (uses your show's B-roll retrieval preferences: tags / material_class / facets) | config `defaultColumn` → built-in default show |
444
- | `--lay <n>` | How many candidate tracks to lay (`0` = produce the plan only, lay nothing) | `1` |
445
- | `--top-k <n>` | Candidate cap per query (overrides the dispatch's shots; server cap is 50) | dispatch value |
446
- | `--material-class <c>` | Material type `real_shot` \| `concept` (matrix-member endpoint only; overrides the show policy) | show policy |
447
- | `--score-floor <f>` | Fill-confidence floor: segments scoring below this are not used and the slot stays empty — empty spots **expose the black bed track** (laid by default; only `--no-black-bed` exposes the main track instead). Raising it shrinks the candidate pool, and a span that cannot be filled at all becomes pure black over the talking-head, so check the hole warnings after adjusting | `0.2` |
448
- | `--no-black-bed` | Do not lay the solid black bed track (one is laid by default) | laid by default |
449
- | `--force-relay` | Strip and re-lay even when you have already edited a candidate track in the client (by default it refuses and keeps that track) **this deletes the `broll-raw-*` material registrations of confirmed source clips, orphaning those files on disk** | off |
450
- | `--out <file>` | Write ad-hoc results to a file; for `matrix fetch`, the raw-footage output directory (never the Jianying draft folder) | stdout / `./matrix-fetch/` |
451
-
452
- **`matrix fetch <clip_id...>` (pull raw footage during the fine cut, project-independent)**: for materials you have **searched with billing** (hits in the grant ledger), re-signs fresh download links for free by clip_id and lands them as `<clip_id>.<ext>` — when the rough cut is already exported to Jianying and one more B-roll is needed, you can pull the raw file locally and drag it straight in without going back to the client app. The flow is always **two-step**: pick clip_ids from `matrix search` → `matrix fetch` to pull (fetch itself is free of charge, performs no search, and has no confirmation gate). **Grants are persistent**: the 24h-expiring signature is no obstacle a clip searched three days ago still fetches fine. Ungranted items are reported one by one as "not granted" with the way out (run one billed search for that keyword to obtain the grant) and never block the rest; one batch 500. **The initial scope covers video clip raws only** (the re-sign surface for image/audio materials is not open yet; such ids land in missing with a hint). Outputs never enter `.gtrk` and never land in the Jianying draft folder; material added inside Jianying does not flow back into the project (export is one-way).
453
- | `--json` | Machine-readable: stdout carries only the result JSON | off |
454
-
455
- > **Beat windows are re-projected on the spot**: in dispatch-consumption mode, **before the first cloud retrieval**, each beat's `[track_st, track_ed]` is recomputed from "`transcript` × the current `.gtrk`", and retrieval, `broll-plan.json` and track laying all use the recomputed values (`--lay 0` obeys the same rule; ad-hoc `search` is unaffected). The timecodes in `dispatch.json` are only a **projection-time snapshot**, used as a fallback solely when re-projection is impossible — **so after editing the talking-head track you can run this command directly without re-running `gtrk split`**. `--json` always emits `reprojection:{mode,degraded,reason?,drifted,max_offset,shrunk,dropped}`; beats with **zero surviving span** after re-projection are skipped (no retrieval quota is burned on them and nothing is laid). If re-projection is impossible (missing transcript / project not found / no talking-head material on the main track) → it **degrades to the snapshot with a warning and a `--json` marker**, while retrieval and the plan still complete instead of hard-failing; behaviour for non-v1 projects is unchanged (the plan lands first, then the version gate exits non-zero).
456
- >
457
- > Candidates' `preview_url`/`cover_url` **are unsigned and never expire** (once the local proxy is on disk it is always reused); what carries a signature and expires in roughly 24 h is the **source `url`**, re-signed by the client's "confirm source clip" flow — **you do not need to re-run this command just to re-sign**.
458
- >
459
- > **Re-running strips and re-lays, but never touches tracks you edited**: candidate tracks are identified by "material prefix + last round's registration fingerprint", no longer by track number (saving in the client renumbers all overlay tracks). Once a candidate track is judged "edited by you" (a clip was changed, or you confirmed the source clip in the client so the material became `broll-raw-*`), this run **lays nothing at all**: no track is stripped, no track is appended, `.gtrk` is byte-for-byte unchanged, `broll-plan.json` is still produced, and the command reports "which track / what evidence / what to do next" and exits non-zero (`--json` emits `{ok:false, refused:[…]}`). Add `--force-relay` to force a re-lay.
460
- >
461
- > **Material-on-disk self-check**: after writing back the project it verifies that every `materials[].path` really is on disk (**read-only, reports without touching anything**). Relative paths are always resolved against the **directory containing the `.gtrk` file** (`<output>/gtrk/`). `--json` emits `integrity:{ checked, counts, dangling:[…], danglingReferenced, danglingOrphan, external:[…], noPathIds:[…] }` — `dangling` is the complete list of **broken references** among project-owned materials (registered but missing on disk), each flagged with **whether the timeline references it** and where (a referenced one means that span has no media to show, far worse than an orphan); missing absolute paths are counted separately as `external` (an unmounted external drive looks like this too, so it does not pollute the main verdict); http(s) materials are only counted and **no network requests are made**. **This informs, it does not block**: broken references do not change `ok`, do not change the exit code, and no material entry or file is deleted. They are usually historical residue (e.g. an interrupted "confirm source clip" download); the fix is to re-confirm the source clip in the client or delete that clip. Runs that never wrote back (`--lay 0` / refused / missing project) **emit no `integrity` field** — absence means "not checked this time", not "checked and clean".
462
- >
463
- > **The solid black bed track**: by default a solid black track is laid beneath all candidate tracks and above the talking-head main track (`struct_meta.broll.black_track` records its `track_index`), covering the full landed beat envelope so that during B-roll (including the empty spots on candidate tracks) the talking-head picture underneath is not exposed. **The cost is "black holes"**: wherever candidate tracks are not filled, pure black covers the talking-head, and track laying computes exactly that `--json` always emits `lay.blackBedHoleSec` plus per-span `lay.blackBedHoles`, and a non-fatal warning is added when a single span is 3 s or a single beat's ratio is ≥ 15 % (it does not change the exit code or block laying). Use it to adjust `--score-floor`, switch to `--no-black-bed`, or patch by hand in the client. The bytes land at `assets/builtin/solid-000000-<W>x<H>.png`, sharing an id namespace with the client's built-in solid material and reused idempotently. Do not delete it by accident when removing candidate tracks; to swap footage, drag onto a candidate track's clip and **not onto the black bed** — since client 0.2.10 (force-updated release on 2026-07-31) **dropping onto the black bed is rejected outright with a message**. On clients older than 0.2.10 (force update not yet pulled) the old behaviour silently creates a new video track and inserts there; if it lands in the lower half you cannot see it in the preview at all (one `Ctrl+Z` undoes the whole thing) restart the client first to pick up the force update. If you do not want the black bed, re-run with `--no-black-bed` and it is stripped clean.
464
-
465
- **Local-footage mode (`matrix index` / `--local`)**: footage does not have to live in the cloud library retrieve and lay tracks straight from your local footage folders (video and images mixed):
466
-
467
- ```bash
468
- gtrk matrix index --dirs <folder1,folder2> # ① build a slice-free index: content-fingerprint incremental, resumable; renames/moves are not recomputed
469
- gtrk matrix --local --dirs <folder1,folder2> --project <dir> # local retrieval + track laying (--lay 0 = plan only, no laying)
470
- gtrk matrix lay --project <dir> [--plan <path>] # ③ consume the (edited) plan and lay tracks, zero retrieval cost
471
- ```
472
-
473
- - **Your footage never leaves your machine**: only 512px sampled frames are sent to Gitruck Cloud's own embed endpoint for vectorization, discarded on arrival; results reference your local originals by absolute path (no downloads, no proxies). Indexing is metered by frames actually sampled (pre-held before the run, settled to actual usage afterwards); text-side retrieval costs zero credits.
474
- - **Images are first-class**: images are indexed, retrievable and layable; when selected, an image goes through cloud `image_move` and lands as a 5-second camera-move video — **the image itself does go to the cloud** (2 credits per image, summarized for confirmation before laying; same image + same params is reused forever, never re-billed). Zero images to the cloud → `--no-image-broll`.
475
- - **No material reuse**: within one laying round each material unit is used once globally (local video per scene, images per file); when candidates run dry, slots stay empty rather than repeat; `--dedup-scope material` tightens to file level.
476
- - **Projects containing local footage cannot cloud-render**: submission is rejected (`local_broll_cloud_render_rejected`) — produce locally in the desktop client or via `gtrk render`.
477
- - **Optional atoms**: `matrix describe --plan <path> [--top-k N]` / `--materials <a,b>` understands candidates on demand (VLM description / tags / quality mark / watermark·subtitle·black-border·blur signals; 1 credit per frame, results injected into the plan and cached locally, cache hits are free, >20 frames triggers a confirmation guard); `--source-window <start,end>` filters by source-time window (only with `--local`; the film-commentary pattern "segment N of the narration gets footage from around segment N of the film"); `matrix lay --mark-weight <0..1>` blends describe's quality mark into candidate ranking (fused score = sim×(1-w)+(mark/100)×w; reorders only, never changes admission; candidates without a cached mark are treated as neutral).
478
- - **Index knobs and score scale**: `--scene-threshold` tunes scene-split granularity, `--stability-threshold` collapses static-camera scenes to fewer sampled frames, `--rebuild` forces a rebuild (describe caches are kept); the index is not portable across machines (keys are absolute paths just re-run `index` on the new machine). Local score scale differs from the cloud's (a perfect hit can score as low as ~0.25), so do not raise `--score-floor` on cloud instincts.
479
-
480
- Orchestration recipes (pure matching / describe-then-lay / time-window / footage-first scripting / three-layer stacking) and the plan-editing contract live in the bundled skill `/gtrk-matrix`.
481
-
482
- ### `gtrk mg` — MG motion-graphics particles (lay / lint / status / render)
483
-
484
- Consumes the `dispatch.mg` dispatch landed by `gtrk split`, laying html-particle assets produced by **your show's MG skill** into the `.gtrk` project's `beat_track`. Four modes are dispatched by the first positional word: **no argument = lay**, `mg lint <file>` = single-file validation, `mg status` = orchestration dashboard, `mg render <file>` = standalone particle cloud render (project-independent; the fine-cut supplement channel). The old name `gtrk rrv` remains a deprecated alias (it prints a notice; prefer `gtrk mg`).
485
-
486
- | Parameter | Purpose | Default |
487
- |---|---|---|
488
- | `--project <dir>` | The oralcut / split output folder (locates `split/dispatch.json` and the `.gtrk` project) | |
489
- | `--dispatch <path>` | Explicit `dispatch.json` path (fallback for non-standard layouts) | Derived from `--project` |
490
- | `--only <beat>` | Run a single beat only (takes a **beat id** such as `B12`, not a `composition_id`; the main particle and its `-aux<n>` overlays are selected together). **True incremental merge**: only the matched particles are re-laid, and every other already-laid particle on the track (including your manual tweaks) is preserved as is | all |
491
- | `--lint-only` | Lint only; lay nothing and write nothing back | off |
492
- | `--replace-all` | Explicitly authorize a **full track reset**: no incremental preservation, the whole track is stripped and re-laid **this deletes every other already-laid particle on the track** | off |
493
- | `--duration <sec>` | **Required in render mode**: the explicit duration anchor (seconds) standalone mode has no slot envelope, so this value is at once the lint envelope, the output duration and the billed duration | — |
494
- | `--format <fmt>` | Render-mode output format: `qtrle` only for now (Jianying-readable transparent MOV; `webm` is explicitly refused Jianying cannot read VP8-alpha) | `qtrle` |
495
- | `--out <dir>` | Render-mode output directory (never writes into the Jianying draft folder — dragging into Jianying is your move) | `./mg-render/<composition_id>/` |
496
- | `--yes` | Render mode: skip the billing-estimate confirmation | off |
497
- | `--json` | Machine-readable: human logs go to stderr, stdout carries only the result JSON | off |
498
-
499
- - **Laying** (`gtrk mg --project <dir>`): reads `dispatch.mg` for each beat takes the source particle from `<project>/mg/<composition_id>.html` → lints → lays it into `beat_track` and atomically writes `struct_meta.mg` back into `.gtrk` (self-produced tracks are registered idempotently in `lay_tracks`; a re-lay strips the previous self-produced items before appending, and user-added tracks are never touched). Whether a particle is a "transparent overlay" or a "full-screen bed" is decided by `opaque`, inferred from the particle HTML's root `background`. Beats with a missing HTML file or a failed lint are counted in `skipped` and do not block the rest.
500
- - **The stripping surface ≠ "what gets laid this run", and ≠ "every registered track"**: `--only <beat>` **strips only the matched particles** (true incremental merge) — every other already-laid particle's clip / material / registration entry is **preserved as is**, together with any manual tweaks you made in opencut (what is preserved is the existing clip itself, not a rebuild from the registration, so transparency `opaque` is not lost); those preserved entries are **not re-linted and their source HTML is not re-copied** (the project is self-contained, so deleting files under `<project>/mg/` does not matter). A full re-lay is still "strip clean, then rebuild the whole track", with **one exception**: particles that are in this dispatch but failed to land (missing HTML / failed lint / zero surviving span after re-projection) keep their previous round's clip on the track (a broken new one must not destroy the working old one); conversely, already-laid entries **no longer present in the dispatch** are still stripped (a plan change ≠ something broke). To strip every other already-laid particle too, authorize it explicitly with `--replace-all`.
501
- - **The material table does not accumulate**: materials are stripped by "**self-produced identity × zero references**" (self-produced = a `mg-`/`rrv-` prefix **or** living under the CLI-exclusive `assets/mg/` with a filename in the self-produced registry), and **it deliberately does not trust the client-rewritable `html_material` prefix** so re-laying after editing the project in opencut still strips old materials, the `mg-` material count **always equals the number of particles on the track**, and historical duplicate/orphan entries are cleaned up along the way. **Non-self-produced materials are never touched** (`broll-*` / `ex-solid-*` / anything you added, even with zero references); self-produced materials still referenced by a surviving clip are also not stripped (it will never strip a clip into a broken reference); the html copies under `assets/mg/` on disk are never deleted.
502
- - **"Nothing matched" is not a clear-everything instruction**: when `--only` matches nothing, `dispatch.mg` is empty/missing, or every entry in this run was skipped, **while the track already has laid particles**, the write-back is refused (that is a signal that the dispatch or the selector is broken). Add `--replace-all` if you really mean to clear it. A first-time lay (no existing laid entries on the track) is exempt and completes normally, reporting `laid=0`.
503
- - **Slot windows are re-projected on the spot**: before laying and linting, each queue entry's `[track_st, track_ed]` is recomputed from "`transcript` × the current `.gtrk`", and thereafter the lint slot envelope (house rule ⑦) and the laid clip duration both follow the recomputed values (`--only` obeys the same rule; aux particles re-project against **their own** span and are not conflated with the main beat window). The timecodes in `dispatch.mg` are only a **projection-time snapshot**, used as a fallback solely when re-projection is impossible — **after editing the talking-head track you can lay directly without re-running `gtrk split`**. `--json` always emits `reprojection:{mode,degraded,reason?,drifted,max_offset,shrunk,dropped}` (including under `--lint-only`). Entries with **zero surviving span** after re-projection are skipped and counted in `skipped` (no HTML is copied and nothing is laid back from the snapshot); if re-projection is impossible (missing transcript / project not found / no talking-head material on the main track) it degrades to the snapshot with a warning and a `--json` marker, and the exit code is unchanged; behaviour for **non-v1** projects is unchanged (the laying path's version gate exits non-zero, while `--lint-only` still produces its report). A successful lay appends this run's timecode provenance (`timecode_source` / `reprojected_at`) into `struct_meta.mg`.
504
- - **lint** (`gtrk mg lint <particle.html> [--dispatch <path>]`): a purely local static check of the machine-decidable subset of the house rules for a particle HTML (wrapped in `<template>`, `data-composition-id` + 1920×1080, `gsap.timeline({ paused: true })`, registration in `window.__timelines`, no `Math.random` / `Date.now`, self-contained with no relative external links, root `background` consistent with `opaque`, …); when `--dispatch` is given it also checks that the `composition_id` matches the dispatch. Any fatal item exits non-zero and reports every reason.
505
- - **Expected-id consistency** (`1-cid-expect`, **fatal**): the `data-composition-id` inside the HTML must equal the expected id (when laying, the dispatch entry's `composition_id`; for `mg lint`, the filename but only when it matches the dispatch or looks like `…-B<digits>[-aux<n>]`, so a renamed copy such as `./tmp.html` is not compared). This guards against "copying `<id>.html`, renaming the file and forgetting the id inside" laying would write a clip/material named after the file while the file registers a different `__timelines` key and fights the same-named particle over the same style scope.
506
- - **House rule ⑦, timeline length estimation** (`7-fill-slot` / `7-no-estimate` / `7-infinite-repeat`, **always non-fatal, never blocks laying**): when the slot envelope is known (per particle when laying; for `mg lint --dispatch` when it matches a dispatch entry) it computes a **static lower bound** on the GSAP timeline degrading call by call, counting whatever it can parse (`duration×(repeat+1) + repeatDelay×repeat`, with `yoyo` adding no time), while calls with expression positions or non-literal durations are **skipped and not counted** (ignoring some calls still yields a valid lower bound). Estimate < envelope → warning; nothing computable at all an explicit notice that "length could not be estimated statically, house rule ⑦ was not verified, and it must be accepted against the real engine's seek" (**never silent**: "could not compute" and "computed and passed" are distinguishable in the output); containing `repeat:-1` a warning that "an infinite loop makes the total length Infinity, so house rule ⑦ cannot be verified statically; please use a finite repeat computed from the slot". The real criterion is always the render engine frame by frame; this item is only a reminder layer.
507
- - **House rule ⑧, repeated-primitive merging** (`8-primitive-merge`, **always non-fatal, never blocks laying**): identifies mergeable batches of `line` / `rect` / `path` / `polyline` / `polygon` that are "created inside a loop, or by a named factory called in a loop; landing under the same parent node; and not driven by per-element animation". Only batches whose purely numeric loop trip counts sum to **≥ 8** under the same parent are reported; when bounds involve `.length` or named constants and cannot be computed it still reports "count unknown" without constant folding; elements with per-element `gsap.set` / tweens, or used as a tween's first argument, are excluded. This item only points out "there is a batch of repeated primitives here that can be merged **losslessly**, pixel-identical after merging" it is **not a risk verdict**: a hit does not mean the particle will reproduce a defect, and a miss does not mean it is safe. The real criterion remains sampling frames from a real render.
508
- - **Callback and seek semantics** (`x-callback-driven` / `x-engine-api-override` / `x-raf-interval`, **always non-fatal, never blocks laying**): aligned with the same-named section of the contract (added 2026-07-26). GSAP `seek(t)` suppresses callbacks by default tweened properties still interpolate, but DOM writes inside `onUpdate` do not run, and the failure mode is **the picture freezing at its initial state rather than going black**. The contract places the guarantee on the **engine side** (fixing a frame MUST use `seek(t,false)` / `time(t)` / `progress(p)`), so a particle **driving its picture from callbacks is a compliant style**; these three lint items are merely **sentinels**: `x-callback-driven` = callbacks write the DOM with no seek fallback anywhere (it stays silent when a fallback exists, to avoid nagging); `x-engine-api-override` = the particle overrides `tl.seek` at runtime or replaces `__timelines[…]` with a wrapper object (which would override the engine's explicit `seek(t,true)` and stops working the moment the engine switches to `time()`/`progress()`; a transitional state); `x-raf-interval` = it contains `requestAnimationFrame(` / `setInterval(` (its own clock is not driven by seek, i.e. frozen). All three MUST NOT be fatal "driving the picture from callbacks" is not a violation.
509
- - **status** (`gtrk mg status --project <dir>`): summarizes the MG pipeline total beats in `dispatch.mg` / how many source HTML files exist / how many are laid into `.gtrk`, annotating each beat (missing HTML / produced but not laid / laid).
510
- - **render** (`gtrk mg render <particle.html> --duration <sec> [--out <dir>] [--yes]`): renders a single particle in the cloud, **independent of any project**, into a Jianying-readable qtrle transparent alpha MOV (the fine-cut supplement channel when the rough cut is already exported to Jianying and one more motion graphic is needed, you can add it without going back to the client app). The chain = lint upfront (envelope = `--duration`; any fatal item is blocked locally, zero submission, zero billing) **billing-estimate confirmation** (live price lookup; the CLI has no local HTML render engine, so the cloud billed task is the only path for standalone particles; `--yes` skips the prompt) inline submission to the cloud `<composition_id>.mov` landed with `task.json`/`result.json` breadcrumbs (recoverable by task_id after a crash). **Scope**: qtrle only for now (`--format webm` is explicitly refused Jianying cannot read VP8-alpha), 1920×1080 particles only (the contract has no portrait/odd-canvas opening), and `--duration` is required. The output never enters `.gtrk` and never lands in the Jianying draft folder; qtrle is lossless and relatively large, suited to seconds-long particles. Note it shares a word with `gtrk render` (full-video rendering) but is a different thing.
511
-
512
- `--json` output: `{ ok, mode:"lay"|"lint"|"status", … }` (each mode carries its own fields, e.g. `laid` / `skipped` when laying, per-beat status for `status`). Laying mode additionally carries **`track_total`** (how many laid particles currently exist on the track), **`kept`** / **`kept_ids`** (how many are **left over from the previous round** and not re-laid this time, plus their `composition_id` list) and **`removed`** (how many old self-produced particles were stripped this run) `laid` (this run), `track_total` (total on the track) and `kept` (left over) **must be read together**, and `track_total = laid + kept` always holds. Reading `laid` alone makes "lay 1, strip 20" look identical to "patch in 1", and reading only the first two hides the cost that "a few particles on the track are not from this round" (`kept_ids` and `skipped` overlap: something that failed to land this round is still there from the previous one). When not fully green it also carries a machine-readable **`reason`**: `skipped` (some were not laid) / `empty_queue` (**write-back refused**, the project was not modified, with `refused:true` and `blocked[]`) / `no_project` (project missing, nothing laid). Runs that actually wrote back also carry **`integrity`** (the material-on-disk self-check, identical in name and shape to `gtrk matrix`; see the previous section).
513
-
514
- > **Exit codes**: an `ok:false` from laying or `--lint-only` **always comes with a non-zero exit** (including the ordinary mid-loop case of "some beats were skipped"). Agents should not read non-zero as "the command crashed" judge by `reason` / `skipped`.
515
-
516
- > **Aux overlay particles**: if `gtrk split` dispatched an `overlay` particle in some beat's `aux_layers`, it derives a `<beat>-aux<n>` composition entry into `dispatch.mg` — `gtrk mg` lays it too, giving you "a main visual on the base track plus a transparent conceptual diagram stacked on the same span".
517
- > **Dual-read compatibility**: `dispatch.mg` (also reads the old `rrv_mg`), the source directory `mg/` (also reads the old `rrv/`), the material prefix `mg-` (also reads the old `rrv-`) — projects created before the de-branding need zero migration.
518
-
519
- ### `gtrk project init` / `gtrk audio lay` — audio-first project atoms (voice-over first)
520
-
521
- Project entry points that start from **a voice-over** instead of a talking-head raw: with the voice-over in hand (TTS-synthesized or self-recorded), `project init` builds the `.gtrk` project, and `gtrk split --project` continues the production pipeline as usual; `audio lay` adds an audio track (BGM/score) to any project.
522
-
523
- | Command | What it does |
524
- |---|---|
525
- | `gtrk project init --tts-task <task_id>` | **Main path**: references a completed `audio_tts_clone` task the server hands over the audio and sentence timecodes directly (zero ASR, zero extra billing); the audio download lands in the project's `audio/` |
526
- | `gtrk project init --audio <voice-over> --transcript <transcript.json>` | **Fallback path**: your own voice-over audio plus its sentence-timecoded transcript as a pair (produced by `gtrk transcript <voice-over> --json`; for TTS-synthesized voice-overs take the main path instead of re-running ASR) |
527
- | `gtrk audio lay --project <dir> --file <bgm.mp3>` | Appends an audio track to the project; **idempotent same-source replacement** (re-running with the same source replaces instead of piling up tracks; zero-reference protection when stripping the old one); `--volume <0..1>` (default 0.3, bed volume), `--offset <ms>` sets the in-point |
528
- | `gtrk audio lay … --beat-align` | Cloud beat analysis (`audio_music_analyze`, billed once) snaps the in-point to the nearest downbeat; without a key / on analysis failure / out of range it degrades to no alignment — the command never fails over it |
529
-
530
- `project init` also takes `--canvas <WxH>` (default 1080x1920), `-o/--out`, `--reupload`, `--no-open` and `--json` with the same semantics as `oralcut`; with `--json` both commands emit a single-line result JSON on stdout (human logs go to stderr).
531
-
532
- ### `gtrk tool <name> [inputs...]` the single-shot tool family
533
-
534
- Standalone single-request capabilities, kept separate from the pipeline's lane commands (`oralcut`/`split`/`matrix`/`mg`). **A top-level command dispatched by the first positional word** (no parent/child commands): `gtrk tool <name> [inputs...]` runs a tool (multi-file image tools accept several paths, and the order is the assembly order), `gtrk tool list` lists them all. One tool = one thin descriptor (input category / payload assembly / artifact mapping / billing / availability gate), sharing a runner that performs "validate upload (fingerprint cache, auto-chunked 256 MiB) → submit → poll → stream-download to disk → `task.json`/`result.json` breadcrumbs" — adding a tool means adding one descriptor, never writing orchestration.
535
-
536
- | Tool | Input | Output | Billing | Status |
537
- |---|---|---|---|---|
538
- | `image_move` | One image; optional `--motion` picks one of 26 camera moves | Camera-move video (geometry derived from the source orientation: landscape 1920×1080 / portrait 1080×1920) | Queried live before the run | Live |
539
- | `image_matting` | One image | Transparent-background png (`--param` can request a backing plate) | Queried live before the run | Live |
540
- | `image_blackborder_remove` | One local image | Image with black borders removed | Queried live before the run | Live |
541
- | `image_canvas_adapt` | One local image; optional target width/height and `normal` / `rectangle` / `square` | Aspect-adapted image | Queried live before the run | Live |
542
- | `image_purify` | One local image (only material you have the rights to process) | Image cleaned of watermarks, logos or overlays | Queried live before the run | Live |
543
- | `video_matting` | One video (**≤ 10 minutes**, uploaded as-is with no proxy) | Transparent-background webm | Queried live before the run | Live |
544
- | `video_blackborder_remove` | One local video | Video with black borders removed | Queried live before the run | Live |
545
- | `video_canvas_adapt` | One local video; optional target width/height, clip range, canvas mode and audio-free output | Aspect-adapted video | Queried live before the run | Live |
546
- | `video_stabilizer` | One local video; optional `fast` / `exp` / `turbo` | Stabilized video | Queried live before the run | Live |
547
- | `video_vaporwave` | One local video; the filter takes an exact preset name | Vaporwave-filtered video | Queried live before the run | Live |
548
- | `video_purify` | One local video; optional `full_screen` / `subtitle` / `custom`, `ffmpeg` / `raft` and a normalized ROI (only material you have the rights to modify) | One cleaned video | Queried live before the run | Live |
549
- | `video_upscale` | One local video (**≤ 1 minute**); optional `2` / `3` / `4`× and `Reality` / `Anime` | One upscaled video | Queried live before the run | Live |
550
- | `video_interpolate` | One local video; optional `2` / `3` / `4`×, with no extra one-minute limit | One frame-interpolated video | Queried live before the run | Live |
551
- | `video_segment` | One local video; optional `--detector content\|adaptive`, `--threshold` | Shot-range structure in `result-output.json` (structured data, not a downloadable file) | Queried live before the run | Live |
552
- | `video_ai_segment` | One local video; optional `--segment-mode scene\|shot_type\|narrative\|subject` | Semantic shot structure in `result-output.json` (structured data, not a downloadable file) | Queried live before the run | Live |
553
- | `video_motion_cut` | One local video | Camera-move / highlight segment structure in `result-output.json` (structured data, not a downloadable file) | Queried live before the run | Live |
554
- | `video_speaker_detect` | One local video; optional `--language`/`--max-faces-per-frame`/`--detect-body`/`--track-sample-fps` (GPU heavy) | Visible-speaker structure in `result-output.json` (the time base follows the server output) | Queried live before the run | Live |
555
- | `video_face_track` | One local video; optional `--sample-fps`/`--max-faces`/`--min-face-ratio`/`--enable-body-match`/`--similarity-threshold`; `time_ranges` goes through `--params-json` (GPU heavy) | Person id / time span / trajectory structure in `result-output.json` (the time base follows the server output) | Queried live before the run | Live |
556
- | `audio_tts_clone` | **No file**: one of `--text`/`--text-file` (≤ 5000 characters) plus a required `--speaker`; optional language/format/speed/segmentation/subtitles | Voice-over audio wav/mp3 (plus optional subtitles); billed by character count — the unit and unit price come from what `gtrk tool list` shows live | Queried live before the run | Live |
557
- | `video_ai_subtitle` | One video or audio file; `--language <code>` required; optional `--translate-language`, `--need-render`, `--need-pure`, `--subtitle-type`, `--subtitle-color`. By default only locally extracted audio is uploaded (the raw file never leaves your machine) | `.ass` subtitles + optional burned-in / subtitle-stripped `.mp4` + `result-output.json` (summary + word-level timeline) | Queried live before the run | Live |
558
- | `subtitle_translate` | One **subtitle file** `.ass` / `.srt`; **both** `--language <code>` and `--translate-language <code>` are required; optional `--output-format`, `--line-mode`, `--bilingual`, `--subtitle-type`, `--subtitle-color`, `--canvas <WxH>`. No speech recognition | Translated subtitles `.ass` or `.srt` + `result-output.json` (entry counts + degradation flags) | Queried live before the run | Live |
559
- | `video_long2short_pro` | One long video (uploaded whole); `--language <code>` required; optional `--output-language`, `--main-topic`, `--output-size`, `--no-jump-cut`, `--duration-pref`, `--max-clip-sec`, `--split-screen`, `--split-orientation`, `--speed-factor`, `--no-camera-move`, `--no-subtitle`, `--subtitle-translate-language` | Finished clips `clip{i}.mp4` + the human-readable report `clips.md` (including polish-degradation details) + `result-output.json` | Queried live before the run | Live |
560
- | `audio_separation` | One audio file; optional `--mode fast\|turbo` | Vocal and accompaniment audio (one or two items, depending on what is returned) | Queried live before the run | Live |
561
- | `audio_speaker_split` | One audio file; optional `--only-struct` | Per-speaker `.wav` stems + a `spoken_list` timeline (`result-output.json`) | Queried live before the run | Live |
562
- | `audio_stretch` | One audio file; optional `--semitones <n>`, `--speed <n>` (> 0) | Pitch/tempo-shifted audio | Queried live before the run | Live |
563
- | `audio_noise_reduce` | One audio or video file; optional `--prop-decrease 0..1` | Denoised audio | Queried live before the run | Live |
564
- | `audio_silence_remove` | One audio file; optional silence threshold and retained length | Silence-trimmed audio | Queried live before the run | Live |
565
- | `piano_audio_to_midi` | One audio file | A MIDI file `.mid` | Queried live before the run | Live |
566
- | `piano_audio_enhance` | One audio file | High-quality WAV + accompanying MIDI (two artifacts) | Queried live before the run | Live |
567
- | `image_to_square` | One image; optional `--max-line <px>` (≤ 20000) | Square image | Queried live before the run | Live |
568
- | `image_to_live` | One image | A short video of about 4 seconds `.mp4` (silent); or an Android motion photo `.jpg` plus the same clip as a companion `.mp4` | Queried live before the run | Live |
569
- | `image_classic_template` | **Several images** + a required `--main-title`; optional subtitle/mode/ratio/quality/count/layout | Finished cover/collage (text/pic/render groups, possibly several images) | Queried live before the run | Live |
570
- | `image_vertical_stitch` | **Several images** (order = top-to-bottom stitching order) | One vertically stitched long image | Queried live before the run | Live |
571
- | `video_split_screen` | **2–16 video segments** (multiple positionals); the precise tier uses `--clips-json` (entries `{input:0-based index, begin_time_ms, end_time_ms, crop}`, millisecond time base); nine optional layout/aspect/audio parameters | One split-screen video (its length matches the shortest segment) | Queried live before the run | Live |
572
- | `mad` | One material folder (3–10 videos) + optional `--bgm` | An AE master-composition project `.jsx` (AE only) | Only `--bgm` triggers a live price query | Live |
573
-
574
- > Prices come from `gtrk tool list --json` and the anonymous live query printed to stderr before execution; this README stores no price snapshot. `video_matting` probes duration with ffprobe before uploading and rejects anything over 10 minutes outright (nothing is uploaded or submitted — trim it first).
575
- > `mad` is the family's first **local-type "purely local tool with optional cloud extras"**: it runs without a key and triggers no billed job (technique data is delivered through a cloud manifest and cached in `~/.gitruck/mad-cache`, so **the first fetch needs the network and afterwards it runs offline**); only `--bgm` beat-syncing needs a key and triggers one cloud beat analysis. Three degradation tiers (key + beat sync / no key or bad BGM → fixed tempo / cloud failure → degraded) never crash. It produces only `.jsx` and supports AE only.
576
-
577
- The seven shared video tools — black-border removal, aspect adaptation, stabilization, vaporwave, cleanup, upscaling and interpolation — accept only the server's current `video_ext`: `.mp4`, `.avi`, `.mpg`, `.mov`, `.flv`, `.mxf`, `.mpeg`, `.ogg`, `.3gp`, `.wmv`, `.h264`, `.m4v`, `.ts`; `.mkv` and `.webm` are rejected locally. Inputs must be local file paths — the CLI does not download remote videos.
578
-
579
- - `gtrk tool list [--json]` list every tool (name/description/input/output/live price/status); `--json` emits a single-line machine-readable array (including dynamic `billingHint`/`pricing`). **Works without an API key**; prices are queried anonymously through a public endpoint, and on failure the full list is still shown with an unavailable marker.
580
- - `gtrk tool image_move ./photo.jpg [--motion zoom_in_center] [--json]` — image to camera move; artifacts land in `photo-image_move/`. `--motion` picks the camera move explicitly (26 values: 8 pans `up_to_down`/`down_to_up`/`left_to_right`/`right_to_left` plus four diagonals, 9 zoom-in anchors `zoom_in_{up,down,left,right,left_up,right_up,left_down,right_down,center}`, 9 zoom-out anchors `zoom_out_` at the same positions); when omitted the server picks one automatically. `--param width=1080 --param height=1920` overrides the derived geometry.
581
- - `gtrk tool image_matting ./portrait.jpg` / `gtrk tool video_matting ./clip.mp4`image/video matting.
582
- - `gtrk tool image_blackborder_remove ./photo.jpg [--json]` — automatically crops black borders from one image.
583
- - `gtrk tool image_canvas_adapt ./photo.jpg --canvas-width 1080 --canvas-height 1920 --canvas-type rectangle [--json]` — image aspect conversion; omitting the canvas parameters uses the server defaults. Per the actual runtime contract the canvas mode accepts only `normal`, `rectangle` and `square`, not the `fit` from older docs.
584
- - `gtrk tool image_purify ./photo.jpg [--json]` — clean watermarks, logos or overlays from an image you have the rights to process.
585
- - `gtrk tool video_blackborder_remove ./clip.mp4 [--json]` automatically crops black borders from one video while keeping the original audio.
586
- - `gtrk tool video_canvas_adapt ./clip.mp4 --canvas-width 1080 --canvas-height 1920 --canvas-type rectangle --clip-start 12 --clip-end 60 --without-audio [--json]` — video aspect conversion; `--clip-start/--clip-end` are start/end frame numbers, omitted fields use the server defaults, and the canvas mode accepts only `normal`, `rectangle`, `square`.
587
- - `gtrk tool video_stabilizer ./clip.mp4 --stabilizer-method turbo [--json]` — video stabilization; supports `fast`, `exp` and `turbo`, where `exp` is experimental and you should check the result yourself.
588
- - `gtrk tool video_vaporwave ./clip.mp4 --vaporwave-filter "灼熱苦夏" [--json]` — add a vaporwave filter using an exact preset name; omitting it explicitly uses `愈漸升溫`.
589
- - `gtrk tool video_purify ./clip.mp4 --purify-scope custom --purify-method ffmpeg --purify-roi 0,0.78,1,0.2 [--json]` — clean a video you have the rights to modify; the ROI is a normalized `x,y,w,h` and is only used together with `custom`. `raft` supports videos under 20 minutes, `ffmpeg` has no such limit; restoring occluded content is not promised.
590
- - `gtrk tool video_upscale ./clip.mp4 --upscale-times 3 --upscale-type Anime [--json]` — experimental video upscaling; input up to 60 seconds, neither side may exceed 4000 px after scaling, supports `2`, `3`, `4`× and `Reality`, `Anime`.
591
- - `gtrk tool video_interpolate ./clip.mp4 --interpolate-multiplier 3 [--json]` — frame interpolation; supports `2`, `3`, `4`×, does not apply the one-minute limit from older docs, and neither side of the source may exceed 4000 px.
592
- - `gtrk tool video_segment ./clip.mp4 [--detector adaptive] [--threshold 27] [--json]` — mechanical shot segmentation; produces **structured** `result-output.json` (`scene_list` with each range's start/end/duration), not a downloadable file.
593
- - `gtrk tool video_ai_segment ./clip.mp4 [--segment-mode shot_type] [--json]` — semantic shot segmentation; produces `result-output.json` (`categories[].shots[]` with shot size, tags, descriptions and second-level timecodes).
594
- - `gtrk tool video_motion_cut ./clip.mp4 [--json]` — camera-move / highlight segments; produces `result-output.json` (`cut_points[]` with frame numbers, second-level timecodes and motion features).
595
- - `gtrk tool video_ai_subtitle ./clip.mp4 --language zh [--translate-language en] [--need-render] [--subtitle-color 湖蓝]` — AI subtitles: `--language` is required, and it produces `.ass` subtitles + `result-output.json` (LLM summary + word-level timeline). **By default only locally extracted audio is uploaded** (the raw file never leaves your machine, and the geometry is sent along with the request); `--need-render` switches to **burning in locally with ffmpeg** (it errors out if `思源黑体 CN Bold` (Source Han Sans CN Bold) is missing rather than substituting another font); `--need-pure` needs the picture, so adding it uploads the whole video. The `subtitle_type`/`subtitle_color` enums and `content` are documented in the cloud API docs, and `--params-json '{"content":{...}}'` passes them through.
596
- - `gtrk tool subtitle_translate ./movie.ass --language zh-CN --translate-language en-US [--bilingual] [--canvas 1080x1920]` — AI subtitle **translation**: move existing subtitles into another language; **both language parameters are required**. **The line between this and `video_ai_subtitle` is the input shape**: to recognize subtitles from audio or video use `video_ai_subtitle`; to move an existing `.ass`/`.srt` into another language use this one (no ASR re-run, and your existing proofreading is preserved). `--line-mode keep` keeps the timeline line for line with the input (so the track can directly replace the original), while the default `resegment` reads more naturally but changes line counts and timecodes. `.srt` files carry no canvas information, so **always pass `--canvas` for portrait output**, otherwise lines are wrapped for landscape and may run past the edge. Style options only apply to `ass` output; combining them with `srt` output is rejected server-side before any charge.
597
- - `gtrk tool video_long2short_pro ./talk.mp4 --language zh-CN [--split-screen] [--speed-factor 1.1]` — long-to-short **fine cut**: finished clips in one shot, one `clip{i}.mp4` each plus the human-readable report `clips.md` (including polish-degradation details). **Division of labour with `gtrk long2short` (rough cut)**: the rough cut produces editable projects (gtrk/Jianying/Premiere), never uploads the raw file, and hands the result to a human for further editing; the fine cut produces only finished videos, uploads the whole file, and costs roughly twice as much. The deciding question: will you edit it afterwards? If yes, rough cut; if no, fine cut.
598
- - The three above are **analysis-type tools**: their artifact is structured data in `result-output.json` (not downloadable media), so `result.json`'s `resultFile` points at it while `files` is empty and `ok=true` — that is normal.
599
- - `gtrk tool audio_separation ./song.mp3 [--mode turbo]` — vocal/accompaniment separation; low-frequency fields such as `--param need_vocals=false` can still be passed through.
600
- - `gtrk tool audio_speaker_split ./meeting.mp3 [--only-struct]` — speaker diarization: by default it produces per-speaker `.wav` files + `result-output.json` (the `spoken_list` timeline); `--only-struct` emits the structure without cutting files.
601
- - `gtrk tool audio_stretch ./song.mp3 [--semitones -3] [--speed 1.5]` — pitch and tempo shifting; pitch and speed are independent, and `--speed` must be > 0.
602
- - `gtrk tool audio_noise_reduce ./interview.mp4 [--prop-decrease 0.5]` accepts audio or video and always outputs denoised audio.
603
- - `gtrk tool audio_silence_remove ./talk.mp3 [--min-silence-len 800] [--desired-silence-len 200]` — removes over-long silences and writes only the processed audio.
604
- - `gtrk tool piano_audio_to_midi ./piano.mp3` — transcribe piano audio into `.mid`.
605
- - `gtrk tool piano_audio_enhance ./piano.mp3` — piano recording restoration, producing a high-quality WAV as the main artifact plus a companion MIDI.
606
- - `gtrk tool image_to_square ./long.jpg [--max-line 8000]` — long image to square; `--max-line` defaults to 4000 and caps at 20000.
607
- - `gtrk tool image_to_live ./photo.jpg [--output-format motion_photo]` bring a still photo to life. By default the artifact is a silent `.mp4` video of about 4 seconds; `--output-format motion_photo` instead delivers an **Android motion photo** (a single `.jpg` with the clip embedded after the still image, so a gallery plays it on long-press), plus the same clip as a companion `.mp4`. Both formats cost the same. Compatibility: Android galleries that support the standard recognise and play it; **iOS does not** and shows a plain still image; a few Android models may only ever show the still.
608
- - `gtrk tool image_classic_template a.jpg b.jpg c.jpg --main-title "新品速览"` — title + several images into a cover/collage; `--output-pic-count`/`--output-text-count` are clamped to ≤ 20 by the server.
609
- - `gtrk tool image_vertical_stitch top.png mid.png bottom.png` — stitch several images vertically in the order given.
610
- - `gtrk tool video_split_screen a.mp4 b.mp4 --output-ratio 16:9` — simple tier: automatic split-screen layout over the whole clips (reaction / side-by-side comparison).
611
- - `gtrk tool video_split_screen a.mp4 b.mp4 --clips-json '[{"input":0,"begin_time_ms":0,"end_time_ms":5000},{"input":1,"crop":{"x":0.1,"y":0,"width":0.8,"height":1}}]'` — precise tier: specify each segment's millisecond range and normalized crop box by 0-based index; the same file can appear several times to fill several windows.
612
- - `gtrk tool video_speaker_detect ./talk.mp4 --language zh-CN` — detect who is speaking and when on screen, emitting structured JSON (GPU heavy).
613
- - `gtrk tool video_face_track ./talk.mp4 --params-json '{"time_ranges":[{"begin_time":0,"end_time":30000}]}'` — face tracking / identity clustering, optionally limited to time ranges (**in milliseconds**; GPU heavy).
614
- - `gtrk tool audio_tts_clone --text "欢迎收听本期节目" --speaker narrator` — text to voice-over audio (the voice list is in the website docs).
615
- - `gtrk tool audio_tts_clone --text-file 稿子.txt --speaker sweet_female --output-format mp3` — long-form synthesis; by default it follows the speed and segmentation tuned for the chosen voice.
616
- - `gtrk tool mad ./素材 [--bgm 歌.mp3] [--duration 20] [--seed 42] [--refresh] [--json]` — one-click MAD: scan the material folder auto-select techniques a single `.jsx` (run it once in AE 2020+ to get the master-composition project). `--seed` makes it reproducible; `result.json` records the seed, data version, degradation tier and chosen techniques.
617
- - Common flags: `--out <dir>` overrides the output folder, `--param k=v` (repeatable) / `--params-json '<object>'` pass cloud parameters through, `--reupload` ignores the upload cache, `--json` is machine-readable, `--ffmpeg-path <dir>` points at an ffmpeg directory.
618
- - Cloud-type tools without a key an error pointing you at `gtrk init`. A failed artifact download (e.g. an expired link 404) `result.json` records `errors` with `ok=false`, and `task.json` is kept so you can recover by `taskId`.
619
- - Cleanup, upscaling and interpolation are long-running GPU jobs, and their descriptors poll for up to 4 hours. A wait timeout does not mean the job was cancelled; keep `task.json` / `result.json` and recover by `taskId` instead of re-running and paying twice.
620
-
621
- The companion skill is `/gtrk-tools` (one skill covering the whole tool family).
622
-
623
- ### Other
624
-
625
- - `gtrk install [--api-key … -y --skill-agents codex,cursor --all-agents --copy-skills --skills-dir …]` — install everything in one command (skills + config + health check), modelled on Feishu's `lark-cli install`.
626
- - `gtrk init [--api-key … --api-base … --jianying-draft-dir … -y]` — configuration only (interactive or not).
627
- - `gtrk doctor` — health check (including the CLI version and whether a newer one exists).
628
- - `gtrk deps status` — show **where** ffmpeg/ffprobe and the render fonts currently come from (`--ffmpeg-path` / `~/.gitruck` / system / missing), plus version, licence and source-code location.
629
- - `gtrk deps install [--ffmpeg] [--font] [--force]` — install runtime assets from the Gitruck Cloud mirror, **skipping anything already present**.
630
- - **It never downloads silently**: any missing-dependency path only errors out and points at this command (the packages are 30–90 MB and the distributed artifacts carry licence obligations, so a user or agent must trigger it explicitly).
631
- - Downloads are always https with **strict sha256 verification**; anything that fails verification is discarded and never lands. Extraction uses the **system tar** (bundled with Windows 10+/macOS/Linux), pulling in no third-party decompression dependency.
632
- - The resolution order is unchanged: `--ffmpeg-path` `~/.gitruck/ffmpeg` system `PATH`. The mirror only fills the middle slot and **never overrides an ffmpeg you installed yourself**.
633
- - Fonts land in `~/.gitruck/fonts` and are supplied to burn-in through the ffmpeg `ass` filter's `fontsdir`**never installed into the system font table, never written to the registry, never requiring administrator rights**.
634
- - The distributed ffmpeg is a GPLv3 build, and the corresponding source is provided alongside the binaries (see `SOURCE.md` at the distribution point); **downloads carry no additional usage restrictions**.
635
- - `gtrk upgrade [--check]` upgrade the CLI to the latest version + refresh skills (config preserved); `--check` only reports.
636
- - `gtrk skills install [--agents codex,workbuddy,comate,…] [--all] [--copy] [--dir <skills dir>]` install/refresh agent skills on their own; by default the generic adapter and the gtrk supplement layer detect hosts automatically.
637
-
638
- ---
639
-
640
- ## How it works
641
-
642
- ```
643
- 本地 gtrk CLI 同合云 本地三端
644
- ───────────── ───────────── ─────────────
645
- 毛片 ──上传(指纹缓存免重传)──▶ video_oral_cut 智能剪辑 ──产物──▶ 客户端 gtrk/project.gtrk
646
- (一次出 gtrk/剪映/xml) 剪映 自动落草稿目录
647
- 源路径写进 gtrk materials.path PR/FCP 导入 premiere.xml
648
- ```
649
-
650
- - **gtrk** is a true superset of a timeline plus HTML particles, and it is Gitruck Cloud's unified project contract; all three formats derive from the same gtrk file, so their cut points agree.
651
- - The cloud side needs **zero changes** and uses the existing `video_oral_cut`; the CLI only orchestrates (upload / submit / poll / fetch / place / open).
652
-
653
- ## Notes
654
-
655
- - Jianying / CapCut drafts require `draft_content.json` + `draft_meta_info.json` **as a pair** (and they must use exactly those **two filenames** — prefixed variants are not detected) before the app recognizes them. So either configure the draft folder with `gtrk init` or point at it with `--jianying-draft-dir`; otherwise only the content file is produced and you have to import it by hand. The CLI normalizes the filenames when copying into the draft root (`long2short` does the same per clip), while the output folder keeps the clip-prefixed archival names.
656
- - When drive letters differ across machines, config lives under `~/.gitruck/` (user level; the old `~/.gtrk-cli` migrates automatically on first launch), and artifacts default to the raw file's folder.
657
- - Pacing preset strength is decided by the cloud; `--preset` only picks a preset and does not change source trimming.
658
-
659
- ---
660
-
661
- ## Layout
662
-
663
- ```
664
- gtrk-cli/
665
- ├── src/index.ts # commander 入口
666
- ├── src/commands/ # subcommands: install / init / oralcut / long2short / transcript / split / matrix / mg / project / audio / tool / render / doctor / upgrade / skills / …
667
- ├── src/lib/ # cloud / column-config / splitdoc / projection / user-config / jianying / …
668
- ├── skills/ # 打包的框架 skills:oralcut / splitter / matrix / mg / ai-drama / style-maker / transcript / tools / music-visualizer / cover
669
- ├── contracts/ # 框架契约库正本(gsap-emit v1 + handoff→契约映射表)
670
- ├── assets/ # README 配图(介绍图 / Agent 调用示例 / 剪映草稿目录指引图)
671
- └── AGENT.md # 可移植 agent playbook(skill 底座)
672
- ```
673
-
674
- A new command = write `register<Name>(program)` in `src/commands/<name>.ts` and register one line in `src/index.ts`.
1
+ # gtrk-cli (formerly the Tonghe Smart Creation Toolkit)
2
+
3
+ **English** · [简体中文](README.md)
4
+
5
+ <!-- Bilingual pair: edits here MUST be mirrored in README.md (section structure is guarded by test/readme-bilingual.test.mjs). -->
6
+
7
+ > The video-production pipeline CLI for Gitruck Cloud (同合云) — **agents drive cloud jobs, artifacts land locally, and three editing-suite project formats (desktop client / Jianying / Premiere) stay interoperable**.
8
+ >
9
+ > One command turns a raw talking-head recording into an editable, re-cuttable project. The cloud does the heavy lifting, your machine only assembles, and the source video never leaves it.
10
+
11
+ **🔗 [Website](https://cloud.ai-mcn.tv/zh-CN/cli) · [Tutorial](https://hocassian.feishu.cn/wiki/HCFpwoF7SivIFbkKosgcFMcEnxk) · [Pricing](https://hocassian.feishu.cn/docx/DtendXStMogAbJxAOEmcCyC7n3e) · [Quick start](https://cloud.ai-mcn.tv/zh-CN/docs/quick-start) · [Desktop client](https://cloud.ai-mcn.tv/zh-CN/download) · [npm](https://www.npmjs.com/package/@gitruck/cli) · [User agreement](https://hocassian.feishu.cn/wiki/T6UywR8b3ik4Mgk7tP9c1b7Kn0b) · [Privacy policy](https://hocassian.feishu.cn/wiki/ZLRNwlEhfishYtkosUhcofMYnPf)**
12
+
13
+ ![Put AI creation capabilities into your local agent](assets/gtrk-agent-intro.png)
14
+
15
+ ---
16
+
17
+ ## Why gtrk-cli
18
+
19
+ - **One command, three project formats**: upload the raw take → cloud-side smart editing (strips filler, repeats, long pauses) → pull back **desktop client (gtrk) + Jianying + Premiere/FCP** project files → the output folder opens automatically.
20
+ - **Cloud does the heavy lifting, your machine only assembles**: recognition, cutting and alignment all happen in the cloud; locally you only receive the result, and **the source video never leaves your machine** (its path is written into the project, so opening it locally resolves the media directly).
21
+ - **Built for agents**: ships with the `gtrk-oralcut` skill — inside Claude Code / Codex / Cursor / Gemini CLI / TRAE and friends, "cut this talking-head for me" is enough to kick it off. The CLI is the hands, the agent is the brain.
22
+ - **A general-purpose toolbox**: a single binary with parallel subcommands — every `gtrk <xyz>` (oralcut / split / mg / matrix / render …) is a **domain-agnostic driver/tool**; a production flow starts whichever ones it needs and leaves the rest alone, and more drivers can be added later. Modelled on Feishu's (Lark) `lark-cli`. It is currently used for humanities & social-science videos, but nothing in the design is tied to any particular show.
23
+
24
+ ## Features
25
+
26
+ | | Command | What it does |
27
+ |---|---|---|
28
+ | 🎬 | `gtrk oralcut <raw>` | Full talking-head editing loop: emits gtrk + Jianying + Premiere projects in one pass and opens the output folder |
29
+ | ✂️ | `gtrk long2short <raw>` | Long-to-short loop: semantic segment selection + jump cuts on a long video (optional 720p-proxy smart split-screen) → per-clip gtrk + Jianying + Premiere projects (the raw file is never uploaded). **If you only want a finished cut and will not edit further, use fine-cut** `gtrk tool video_long2short_pro` |
30
+ | | Duration cap | For `oralcut` / `long2short`, a source longer than **2 hours is rejected before upload** (nothing is extracted, uploaded or charged). Split it first and run the segments one by one 40 minutes per segment is the house figure: `ffmpeg -ss 0 -t 2400 -i "<source>" -c copy "<source>_seg01.mp4"` (stream copy, takes seconds) |
31
+ | 📝 | `gtrk transcript <local video\|voice-over audio>` | Video/audio to transcript: the original file is not uploaded, only the locally extracted (or, for audio input, transcoded) 16 kHz audio derivative, producing one Markdown file with a summary, timecoded record and plain text; with `--json` it also emits a sentence-timecoded `transcript.json` (the input for the `gtrk project init` fallback path) |
32
+ | 🎵 | `gtrk music-visualizer <audio>` | Music visualization: one songa spectrum-visualizer video (`--template` required, optional background/cover and template/color styling), with the companion driver skill `gtrk-music-visualizer` |
33
+ | ✂️ | `gtrk split [split doc]` | Visual split dispatcher: finished cut × transcript projection → validated beat storyboard (`struct_meta.split` + `dispatch.json`), driving four lanes; `--column <id>` validates against your show's vocabulary |
34
+ | ⚙️ | `gtrk init` | Guided one-time setup (API key + Jianying draft folder), then forget about it |
35
+ | 🩺 | `gtrk doctor` | Health check: config / cloud connectivity / Jianying folder / runtime in one shot |
36
+ | 📦 | `gtrk deps` | Runtime assets: `status` shows where ffmpeg/fonts come from and under which licence, `install` fetches them from the Gitruck Cloud mirror (**must be triggered explicitly never a silent auto-download**) |
37
+ | 🤖 | `gtrk skills install` | Installs the 14 bundled CLI skills into the agents detected on this machine, via the generic `skills` adapter plus a gtrk supplement layer; `--all` covers every registered host |
38
+ | ⬆️ | `gtrk upgrade` | Upgrade the CLI to the latest version + refresh skills (config preserved); `--check` only reports |
39
+ | 🎞️ | `gtrk render` | Render a gtrk project (EDL) locally finished mp4 (requires ffmpeg); output frames are allocated against the **cumulative** timeline (per-clip rounding never accumulates, so the picture cannot drift away from the voiceover); runs a QC pass afterwards and writes `.qc.json` (`--no-qc` skips it) |
40
+ | 🔬 | `gtrk qc <cut>` | Final-cut QC: one decoding pass over the whole file for flash frames, black/frozen frames, clipping, silence and audio/video drift, each with a timecode; `--gtrk <project>` enables project-aware detection of **intra-clip cuts**, `--fail-on error\|warn\|never` gates pipelines via the exit code |
41
+ | 🔎 | `gtrk matrix` | B-roll retrieval + **candidate track laying**: consumes the FILM_BROLL dispatch → produces a candidate list + downloads preview proxies and lays N candidate tracks (`--lay N`, default 1; open it in opencut and toggle track visibility to compare; `--lay 0` produces the list only); `matrix search "<query>"` is a one-off ad-hoc search; `matrix fetch <clip_id...>` pulls raw footage during the fine cut (free re-signing + download for already-granted materials, drag straight into Jianying); **local-footage mode**: `matrix index --dirs <folders>` builds a slice-free index `--local --dirs` retrieves and lays tracks (**your footage never leaves your machine**) `matrix lay` consumes the (editable) plan; `matrix describe` understands candidates on demand |
42
+ | 🎨 | `gtrk mg` | MG motion-graphics particle laying: consumes the MG dispatch → lays html-particle assets (transparent overlay / full-screen bed, produced by your show's MG skill) into the `.gtrk` `beat_track`; `mg lint <particle.html>` runs the statically checkable subset of the house rules, `mg status --project <dir>` is an orchestration dashboard; `mg render <particle.html> --duration <sec>` renders a single particle in the cloud, independent of any project, into a Jianying-readable qtrle transparent MOV (the fine-cut supplement channel); aux overlay particles can be layered on the same span (one beat derives a main particle plus `-aux<n>`). The old name `gtrk rrv` remains as a deprecated alias |
43
+ | 🎙️ | `gtrk project init` | Audio-first project bootstrap: build a `.gtrk` project from a voice-over main path `--tts-task <task_id>` references a completed TTS task (fetches the audio plus sentence timecodes directly, zero ASR); fallback path `--audio`+`--transcript` takes your own voice-over as a pair. Once landed, `gtrk split --project` continues the production pipeline as usual |
44
+ | 🎼 | `gtrk audio lay` | Audio-track atom: appends an audio track to a `.gtrk` project (BGM/score; idempotent same-source replacement, no track pile-up); `--beat-align` runs cloud beat analysis and snaps the in-point to the nearest downbeat (billed once; degrades gracefully without a key or on failure) |
45
+ | 🎯 | `gtrk audio align` | Audio-video alignment part (fully local, zero billing): cross-correlates an external audio recording (lav mic / recorder) against the video to measure offset + confidence; high confidence swaps the track directly (video stream untouched byte-for-byte), low confidence emits an alignment project for the client timeline, then `--resume` reads the confirmed offset back; `--offset` swaps at an explicit offset |
46
+ | 🧰 | `gtrk tool <name>` | Single-shot tool family: image-to-camera-move, image/video matting, image black-border removal / aspect adaptation / cleanup / square conversion / LivePhoto, smart collage covers and vertical stitching (multi-image input), video black-border removal / aspect adaptation / stabilization / vaporwave filter / mechanical & semantic shot segmentation / motion highlights / AI subtitles, vocal-accompaniment separation / speaker diarization / pitch-and-tempo shift, piano-to-MIDI and piano restoration, audio denoising, silence removal, MAD, and more; `gtrk tool list` shows every input/output/live price/status. Single request, single result, shared runner adding a tool means adding one descriptor |
47
+ | 💬 | `gtrk feedback` | Tell us what feels wrong: `gtrk feedback "<one line>" --command <command>`. **Disclosed submission** — when an assistant files it for you it must first read the exact content back to you and only add `--disclosed` once you agree; in a pipe or any non-interactive environment, sending without that declaration is refused outright. Content is redacted before it leaves your machine (local paths, credentials, e-mail addresses, phone numbers and the like are replaced by shape), so what you are shown is exactly what gets sent |
48
+ | 🚧 | `struct` | (planned) convert an existing gtrk project into the three formats |
49
+
50
+ ---
51
+
52
+ ## Getting an API key
53
+
54
+ The CLI calls Gitruck Cloud capabilities, so you need an API key first (it looks like `gc_xxxxxxxx`):
55
+
56
+ 1. Open **[cloud.ai-mcn.tv](https://cloud.ai-mcn.tv)** and sign in — **signing in activates your account**, free trial credits included, no gatekeeping.
57
+ 2. Go to the **[console](https://cloud.ai-mcn.tv/zh-CN/dashboard)** and create/copy your key under "API keys / key management".
58
+ 3. The next step, `gtrk install`, will prompt you to paste it (configure once, reuse locally forever).
59
+
60
+ > Terms of record: [User agreement for the "OpenCut Gitruck Edition" client and the "gtrk CLI"](https://hocassian.feishu.cn/wiki/T6UywR8b3ik4Mgk7tP9c1b7Kn0b) · [Privacy policy](https://hocassian.feishu.cn/wiki/ZLRNwlEhfishYtkosUhcofMYnPf) — **signing in or completing registration on the website constitutes your acceptance**; when you call cloud capabilities from the CLI, you are the party primarily responsible for the legality of the content you process.
61
+ >
62
+ > Quick-start docs: [cloud.ai-mcn.tv/zh-CN/docs/quick-start](https://cloud.ai-mcn.tv/zh-CN/docs/quick-start) · Business enquiries: business@gitruck.com
63
+
64
+ ## Install & first run
65
+
66
+ Requires Node.js ≥ 20.6 (check with `node -v`).
67
+
68
+ ```bash
69
+ # 1) 一条命令装全:命令行 gtrk + /gtrk-oralcut skill + 配置(填 API Key、自动扫剪映目录)
70
+ npm i -g @gitruck/cli@latest && gtrk install
71
+ # 或免全局安装直接用:npx @gitruck/cli@latest install
72
+
73
+ # 2) 剪一条(剪完自动打开产物目录)
74
+ gtrk oralcut "D:/素材/某选题-原始口播.mp4" --script "D:/素材/某选题-文字稿.txt"
75
+
76
+ # 或把本地视频转成一个 Markdown 文字稿
77
+ gtrk transcript "D:/素材/采访视频.mp4"
78
+ ```
79
+
80
+ > Only want the config and not the skills? Use `gtrk init`. For local development: `cd gtrk-cli && bun install && bun run src/index.ts <command>`.
81
+
82
+ The output folder is named `<raw-name>-video-project-<YYMMDD-HHMMSS>/` and contains the `gtrk/`, `jianying/` and `xml/` projects.
83
+
84
+ > **Re-installing will not re-prompt for config**: `gtrk install` / `gtrk init` detect an existing setup and keep it, refreshing only the skills. Add `--reconfigure` to change things (you can press Enter to keep the existing key or Jianying folder).
85
+
86
+ ## Operating map: from zero to a finished video
87
+
88
+ > **You just talk; let the agent do the CLI typing.** Below is the end-to-end route — what comes first, what comes next, and what to do when things go sideways.
89
+
90
+ **One-time setup (once, then forget)**
91
+
92
+ 1. **Install the CLI**: `npm i -g @gitruck/cli@latest && gtrk install` (installs gtrk + skills + your API key in one go).
93
+ 2. **(Optional) Create a show style**: if you want your own visual grammar and vocabulary, tell your agent "**build the style system for my show**" (`/gtrk-style-maker` interviews you and turns the answers into your own skill family plus a show config). **Skip it and you get the default kitchen** — the end-to-end flow still runs.
94
+
95
+ **Per video (an ordered SOP with checkpoints — you talk to the agent, and it is not a one-shot parallel fan-out)**
96
+
97
+ Lanes are laid **in order, with a checkpoint at every step**: first fill the B-roll base layer from all three sources (film footage / your local footage / AI scene clips) → you adjust it → sample frames to check the final composition → only then stack MG (incl. ov) on top. You drive each step by conversation and the agent runs the matching command.
98
+
99
+ **Three entry chains, one merge point.** What your material looks like decides which chain you take; once you hold a project plus its transcript, all three are identical:
100
+
101
+ ```
102
+ 口播链 你对着镜头讲的一条口播 gtrk oralcut
103
+ 短视频口播 / 人文社科杂谈 照稿剪掉重来·口误·长停顿
104
+
105
+ 配音链 你写的一段稿子 → AI 配音 gtrk project init
106
+ 电影解说 / 美食解说 先把配音调舒服,再建工程
107
+
108
+ ③ 长剪短 一条几十分钟的长素材 gtrk long2short
109
+ 播客·圆桌·脱口秀·访谈·直播回放 挑出值得单发的,逐条出工程
110
+
111
+ ══════════ 工程 + 文稿 ══════════ ← 汇合点:往下三条链一样
112
+
113
+ ┌───────────────────────┴───────────────────────┐
114
+ │ │
115
+ 配画面(可选,次序不能跳) 只想快点出片
116
+
117
+ gtrk split 把文稿分段派活
118
+
119
+ gtrk matrix 按文稿铺 B-roll
120
+
121
+ AI 再现(可选) 外部平台出片 → 手动回铺
122
+
123
+ 客户端挑选 抽帧核构图 ← 底轨定稿前别往下走
124
+
125
+ gtrk mg MG 主颗粒 + OV 叠层,最后才叠
126
+
127
+ gtrk audio lay 全片加 BGM(可选)
128
+ │ │
129
+ └───────────────────────┬───────────────────────┘
130
+
131
+ 客户端:上字幕 出片
132
+ (或导出剪映草稿 / PR 工程)
133
+ ```
134
+
135
+ Chain names above: *口播链* = talking-head (you shot yourself: short-form monologue, humanities commentary) · *配音链* = voice-over (you wrote a script: film recaps, food recaps) · *长剪短* = long-to-short (podcasts, roundtables, stand-up, interviews, stream VODs).
136
+
137
+ **Two things to remember**: (1) **lay the bottom first, stack the top last** — B-roll and AI scene clips are both base-layer picture (two legs of one stage), while motion graphics (MG main particles + OV transparent overlays) are the only overlay layer, so stacking before the base is final is wasted work; (2) the final render always happens in the desktop client or your own NLE — the CLI only fills the project.
138
+
139
+ > Full walkthroughs for each chain (artifacts per step, troubleshooting) live in the tutorial's sub-pages.
140
+
141
+ | Step | What you say to the agent | What the agent does | Where you step in |
142
+ |:--:|---|---|---|
143
+ | | "**cut a version** of this talking-head" | `/gtrk-oralcut` → `gtrk oralcut` → three projects + transcript | |
144
+ | | "now **split it into a storyboard dispatch**" | `/gtrk-splitter` → `gtrk split` → `dispatch.json` with four lanes | review the dispatch |
145
+ | | "**lay the B-roll base**" (two legs, one stage) | `/gtrk-matrix` `gtrk matrix` film/local-footage candidate tracks laid; `/gtrk-ai-drama` (skill, no command) → four-part description docs (Chinese/English blocks) | **pick/adjust B-roll in opencut** (toggle track visibility to compare); generate AI clips on an external platform and **drop them back in by hand** |
146
+ | | "B-roll is settled, **check the composition**" | samples frames from the **merged three-source base layer** (an agent discipline, no dedicated command) | **confirm the composition** (subject position / safe areas / facing / brightness) |
147
+ | | "composition looks good, **lay the MG**" | `/gtrk-mg` `gtrk mg` MG (incl. ov) stacked on the settled base layer | fine-tune particles (by hand in opencut) |
148
+ | ⑥ | "**produce the final cut**" | the desktop client's production chain (multi-lane compositing + cloud particle rendering / export to Jianying); `gtrk render` only produces a **main-track snapshot preview** | final polish inside the client |
149
+
150
+ > The order exists for a reason: **AI scene clips belong to the base-layer B-roll family, not to an overlay layer** — the only overlay layer in the pipeline is MG (incl. ov). MG placement shapes itself around the picture and **depends on the final composition of the base layer**, so all three sources (film / local / AI) must land and the composition must be checked before MG goes on. Skip lanes you do not need (an empty queue in `dispatch` simply lays nothing).
151
+ >
152
+ > ⚠️ **Older docs said "④ lay MG → ⑤ AI re-enactment last", reasoning "the later it comes, the higher it stacks" — that mistook work order for layer order, corrected on 2026-08-17.** If your installed skills predate this, run `gtrk upgrade` to pick up the new order.
153
+ >
154
+ > **AI generation is asynchronous**: external platforms can take days of rerolls, and strict serialization would block ④⑤ indefinitely. The gate into ⑤ is therefore "**AI clips are back in ∨ you explicitly say skip for now**"; when you skip, the agent marks the MG particles adjacent to or overlapping the AI spans as "recheck composition once AI clips land" and repeats that list at wrap-up.
155
+ >
156
+ > ③④⑤⑥ all require **going back to the desktop client** to select, polish, re-insert and produce — the CLI lays material into `.gtrk`, and the client turns `.gtrk` into a finished video. See the "**CLI × desktop client**" section below.
157
+
158
+ **When things go sideways**
159
+
160
+ | Situation | What to do (tell the agent, or it handles it) |
161
+ |---|---|
162
+ | You only want the editing project, no visuals yet | Stop after "cut a version": "just the editing project for now" |
163
+ | Lost the report / want the artifacts on another machine | "fetch the previous one by taskId" → `gtrk oralcut-result <taskId>` (skips the cloud re-run) |
164
+ | You want to choose between several B-roll candidates | "lay a few more B-roll candidates" → `gtrk matrix --lay N`, then toggle track visibility in opencut |
165
+ | B-roll fill is poor / there are empty slots | Adjust `--score-floor` / `--top-k` and re-run, or "search a single query" `matrix search "<query>"` to patch it |
166
+ | You want to lay B-roll from your own footage | "use my local footage" `gtrk matrix index --dirs <folders>` to build the index, then `gtrk matrix --local --dirs … --project …` (**your footage never leaves your machine**; see the matrix section in the command reference) |
167
+ | Picture / particles need frame-level polish | Open the project in opencut and adjust by hand (what the agent laid is an **editable project**, not a flattened render) |
168
+ | Cannot connect / config problems | "run a health check" → `gtrk doctor` (config / cloud / Jianying folder / version in one shot) |
169
+ | A new version is out | "upgrade" → `gtrk upgrade` (upgrades the CLI + refreshes skills, config preserved) |
170
+
171
+ ## CLI × desktop client: hands and brain, one `.gtrk` throughout
172
+
173
+ **The standard workflow is never "CLI only" — it is the CLI and the desktop client working together, and the client is an unavoidable part of producing a finished video.** The division of labour:
174
+
175
+ - **CLI = headless assembler (hands / mechanical work)**: it deterministically packs cloud editing results, retrieved B-roll and show-produced particles into the project and atomically writes back `.gtrk` (cut the talking-head / split the dispatch / lay B-roll candidate tracks / lay MG particles). It makes no aesthetic judgements and produces no final cut.
176
+ - **Desktop client = the workbench with a screen (eyes / polish)**: it opens **the same `.gtrk`** so you can look, choose, polish frame by frame, drop AI clips back in, and produce the final video. Installation is the one-liner in the "Upgrade → desktop client" section (OpenCut Gitruck Edition).
177
+
178
+ **`.gtrk` is the handover medium between them** — it is Gitruck Cloud's unified project contract (a true superset of a timeline + HTML particles + `struct_meta`), **written by the CLI, read by the client, in both directions**. So a video advances by **alternating** between CLI and client:
179
+
180
+ ```
181
+ CLI .gtrk ─▶ 客户端打开(自动感知外部改动、先存脏改再刷新、不丢稿)
182
+ ─▶ 你在客户端挑/调/精修 ─▶ 需要就再喊 agent 让 CLI 写下一轮(铺 MG / 铺 AI…)
183
+ ─▶ … 反复 … ─▶ 客户端出片
184
+ ```
185
+
186
+ **These things can only be done in the client (the CLI cannot give them to you):**
187
+
188
+ | Stage | Why it must happen in the client |
189
+ |---|---|
190
+ | **Choosing B-roll candidates** | `gtrk matrix` lays N candidate tracks; you toggle each track's visibility to compare, pick one, and delete the rest — an aesthetic call only a person in the client can make |
191
+ | **MG / particle polish** | The client renders html-particles as **live transparent previews** with frame-level Transform/Blending/Effects tuning |
192
+ | **Talking-head fine cut** | Magnetic main-track ripple editing, manual nudging of cut points / pauses / split-screens |
193
+ | **Re-inserting AI re-enactment** | AI clips generated on external platforms are **dragged into the AI_DRAMA lane by hand** and aligned to their spans (`/gtrk-ai-drama` only emits description docs; the footage is produced externally — see SOP ③: it belongs to the base-layer stage, and MG waits until it has landed) |
194
+ | **Final production** | Multi-lane compositing (overlay / MG / cloud-rendered particles stacked) plus Jianying draft export both live in the client's production chain |
195
+
196
+ > **`gtrk render` ≠ the final cut.** `gtrk render` is a local ffmpeg **snapshot preview of the main track (the rough talking-head cut)** — it merges only the main video and audio tracks and **does not composite overlays (B-roll candidates) / MG particles / AI re-enactment**. For a **real multi-lane finished video** (all lanes stacked, particles cloud-rendered, Jianying draft exported), use the **client's production chain**. In one line: **the CLI puts material into the project; the client turns the project into a video.**
197
+
198
+ ## Upgrading
199
+
200
+ **CLI + skills** (config preserved as-is):
201
+
202
+ ```bash
203
+ gtrk upgrade # 有新版则升到最新 + 刷新 skill
204
+ gtrk upgrade --check # 只看有没有新版,不动手
205
+ ```
206
+
207
+ > If you use `npx` (no global install), you already get the latest every time: `npx @gitruck/cli@latest install`. `gtrk doctor` will also mention when a newer version exists.
208
+
209
+ **Desktop client**: re-run the one-line installer to overwrite-install the latest (per-user, no admin rights, config untouched):
210
+
211
+ ```powershell
212
+ irm https://api.ai-mcn.tv:9000/broadcast/exe/install.ps1 | iex
213
+ ```
214
+
215
+ ## Using it with AI agents
216
+
217
+ Once installed, a single sentence in any agent invokes a gtrk skill:
218
+
219
+ | | |
220
+ |:--:|:--:|
221
+ | ![Calling gtrk from an agent, example 1](assets/agent-example-1.png) | ![Calling gtrk from an agent, example 2](assets/agent-example-2.png) |
222
+ | ![Calling gtrk from an agent, example 3](assets/agent-example-3.png) | ![Calling gtrk from an agent, example 4](assets/agent-example-4.png) |
223
+
224
+ `gtrk install` installs the 14 bundled CLI skills (`gtrk-oralcut`·`gtrk-long2short`·`gtrk-splitter`·`gtrk-matrix`·`gtrk-mg`·`gtrk-ai-drama`·`gtrk-style-maker`·`gtrk-transcript`·`gtrk-tools`·`gtrk-music-visualizer`·`gtrk-cover`·`gtrk-travel-recap`·`gtrk-live-slicing`·`gtrk-talking-head`) into the agents detected on this machine. The mechanism matches lark-cli: gtrk hands its local skill sources to the generic `skills` CLI, which owns agent detection, directory mapping and update rules; gtrk no longer hardcodes per-vendor paths.
225
+
226
+ By default `~/.agents/skills` is the single source of truth, linked into each agent's compatible directory (junctions on Windows); where linking is unavailable the adapter falls back to copying. That way updates touch one canonical copy instead of letting duplicates drift apart. Common commands:
227
+
228
+ ```bash
229
+ # 自动探测已安装的 Agent(等价核心:npx -y skills add <gtrk包根>/skills -g -y)
230
+ gtrk skills install
231
+
232
+ # 只装指定宿主;这里使用通用 skills CLI Agent ID
233
+ gtrk skills install --agents codex,cursor,gemini-cli,trae-cn
234
+
235
+ # 安装到适配器当前支持的全部 Agent(会创建较多宿主目录)
236
+ gtrk skills install --all
237
+
238
+ # 不使用链接,每个宿主各复制一份
239
+ gtrk skills install --copy
240
+ ```
241
+
242
+ `--agents` accepts agent IDs from both the upstream adapter and the gtrk supplement layer. Chinese agents already covered include `trae`, `trae-cn`, `codebuddy`, `qoder`, `qoder-cn`, `qwen-code`, `kimi-code-cli`, `iflow-cli`, `codearts-agent` and `lingma`, plus `workbuddy`, `qoderwork` and `comate` which upstream has not registered yet. Common shorthands — `qwen`, `kimi`, `iflow`, `codearts`, `tongyi-lingma`, `qoder-work`, `baidu-comate` — are mapped automatically. When upstream adds new agents, gtrk can use the new IDs without a release; if an existing script must hardcode a directory, `--dir <skills dir>` still gives you the compatible copy mode.
243
+
244
+ **Agent input UIs are not standardized**: Claude usually surfaces skill names in `/` completion; different Codex clients enter via `$`, `/skills` or a Skills panel; TRAE relies mostly on Skills settings, explicit naming or semantic triggering. So not seeing a Claude-style `/gtrk-*` dropdown does not mean the skill is missing. If a new skill does not show up, refresh the window or start a new session.
245
+
246
+ Then just say "**cut a version of this talking-head**", or explicitly pick `gtrk-oralcut` from your agent's Skills entry point. The agent will ask about the raw file, script and pacing, call `gtrk oralcut --json` to run the loop, verify the artifacts and tell you how to open all three formats. The full portable playbook is in [`AGENT.md`](./AGENT.md).
247
+
248
+ **Hand the whole chain to the agent**: it is not just the talking-head cut — keep going with "split the storyboard", "lay the B-roll", "lay the MG particles", "render the video", and the agent will pair each show-specific production skill with `gtrk split` / `gtrk matrix` / `gtrk mg` / `gtrk render` to run the entire **production pipeline**. **You just talk; leave the CLI typing to the agent** — the "Command reference" below exists so the agent can look up parameters, not so you type them in a terminal.
249
+
250
+ ### Capabilities agents can drive (skill drives command)
251
+
252
+ **Each capability = one skill (the brain — you trigger it, it knows its place in the SOP and handles interaction) driving one gtrk command (the hands — deterministic mechanical work).** Production is an **ordered SOP with a user checkpoint at every step**, not a one-shot parallel fan-out — a `/gtrk-X` skill runs `gtrk X` at the right moment, with your confirmation:
253
+
254
+ | SOP | Driving skill (what you say) | Underlying command (what the agent runs) | What it does |
255
+ |:--:|---|---|---|
256
+ | | `/gtrk-oralcut` | `gtrk oralcut` | Smart talking-head cut desktop client / Jianying / Premiere projects + transcript |
257
+ | | `/gtrk-splitter` | `gtrk split` | Storyboard dispatch`dispatch.json` (A_ROLL/MG/AI_DRAMA/FILM_BROLL, four lanes) |
258
+ | ③ | `/gtrk-matrix` | `gtrk matrix` | **B-roll base · film/local-footage leg**: lays candidate tracks **you adjust/choose** (toggle visibility in opencut) |
259
+ | | `/gtrk-ai-drama` | (no command, pure authoring) | **B-roll base · AI scene-clip leg (same stage as matrix, not last)**: emits four-part description docs (backstory / characters / shots / source text, in Chinese and English blocks) generate on any external platform and re-insert by hand (the artifact is description text with no mechanical tail, same as `/gtrk-style-maker`: skill only, no command) |
260
+ | | (no skill) | (no command) | **Global frame-sampling composition check**: sample frames from the merged three-source base layer and have the user confirm the composition — a hard agent-discipline gate feeding ⑤'s placement decisions |
261
+ | | `/gtrk-mg` | `gtrk mg` | **MG (incl. ov) goes on last** (stacked on the settled, composition-checked base layer) |
262
+ | — | `/gtrk-style-maker` | (no command, builds a show) | A one-time interview that builds your show's style system (skill family + show config, see next section) |
263
+ | | (wrap-up) | `gtrk render` | Render a gtrk project locallyfinished mp4 |
264
+ | ✂️ | `/gtrk-long2short` | `gtrk long2short` | Long-to-short rough cut: semantic segment selection + jump cuts per-clip client/Jianying/Premiere projects (the raw file is never uploaded); **not part of the production SOP**, usable standalone at any time |
265
+ | 📝 | `/gtrk-transcript` | `gtrk transcript` | Local video / voice-over audio one Markdown file with an agent-written summary, timecoded record and plain text; **not part of the production SOP** |
266
+ | 🧰 | `/gtrk-tools` | `gtrk tool <name>` | The single-shot tool family (image-to-camera-move / image & video matting …) single request, single result, **not part of the production SOP**, usable standalone at any time |
267
+ | 🎵 | `/gtrk-music-visualizer` | `gtrk music-visualizer` | One song a spectrum-visualizer video (template + optional background/cover + colour styling), **not part of the production SOP**, used standalone for audience acquisition |
268
+ | 🖼️ | `/gtrk-cover` | (no command, pure authoring) | The two-stage cover workbench: design diagnosis + text-to-image prompts in three sizes and two languages → you generate images on an external platform → an HTML5 typesetting workbench (drag/scroll fine-tuning, one-click export to multiple PNG sizes). Show-specific cover aesthetics are injected through the show config's `style.skills` (`produces:"cover"`); **not part of the production SOP** (it is the "stage zero" companion to distribution) |
269
+
270
+ > **Skill vs command**: `/gtrk-mg` is the **brain** it knows it belongs at SOP step (MG only after all three B-roll sources have landed and the composition is checked), asks for your confirmation, and resolves which particle type to produce from the show config; `gtrk mg` is the **hands** purely deterministic lint + track laying. You trigger the skill by talking, and the skill runs the command for you.
271
+ > The 12 `/gtrk-X` skills above are **framework skills bundled with the CLI** (installed by `gtrk skills install`) — `/gtrk-long2short` independently drives long-to-short, `/gtrk-transcript` independently drives video/audio-to-transcript, `/gtrk-tools` covers only the single-shot tool family, `/gtrk-cover` handles covers, and none of the four belong to the production SOP; `/gtrk-ai-drama`·`/gtrk-style-maker`·`/gtrk-cover` are pure authoring skills (no command). Show-specific **visual style and content** come instead from your own show's production skills (created by `/gtrk-style-maker`, bound through the show config's `style.skills`) and are never hardcoded into these framework skills.
272
+
273
+ **How each lane's actual visuals/content get produced** — what the MG looks like, what tone the AI re-enactment has — is not hardcoded into the CLI. It comes from **your own show's production skills** (created interactively with `/gtrk-style-maker`, kept locally). They are bound through the show config's **`style.skills[].produces`** (the value is the lane name), and **general-purpose drivers** such as `gtrk mg` / `gtrk matrix` consume them accordingly. **The direction is: the CLI drives the show skills** — show skills only supply style/content and carry no "which command to run" orchestration; the framework only knows lanes and pipeline interfaces, and the look always belongs to your show. Without a show, the built-in defaults are used and everything still runs end to end.
274
+
275
+ ---
276
+
277
+ ## Shows and style: a two-layer structure
278
+
279
+ > **The show config is remodelling your kitchen; producing a video is cooking dinner. You do not remodel the kitchen before every dish, but every dish is indeed cooked in the kitchen you remodelled.**
280
+
281
+ The system has two layers on completely different time scales:
282
+
283
+ **[Show layer · one-time / infrequent] = building a show (remodelling the kitchen)**
284
+ Run `/gtrk-style-maker` (a meta skill). It uses a heuristic interview to help you work out **your own** visual grammar — presupposing no dimensions at all: it does not assume you have a narrative structure, a thematic system, or a split between animation and live action. Your dimensions and their values are entirely yours to define. It produces:
285
+
286
+ - Your own executable skill family (written into the current agent's user-level skills directory; a black box, kept local)
287
+ - A vocabulary shared inside the show (referenced by every skill in the family, preventing drift between multiple definitions)
288
+ - The show config `~/.gitruck/columns/<id>.json` (vocabulary + B-roll retrieval preferences + a list of style references)
289
+
290
+ **[Production layer · every video] = cooking (the shape of the flow never changes)**
291
+ Cut the talking-head → split the script → dispatch (B-roll retrieval / motion graphics / re-enactment) → assemble → render. Every step explicitly consumes the current show config: script splitting validates against your vocabulary (`--column <id>` or the config's `defaultColumn`), B-roll retrieval follows your show's retrieval preferences (`broll.column_tag_ids` show tags / `material_class_policy` / facets), and each lane goes through your own production skills.
292
+
293
+ **No show configured? Use the default "kitchen".** Zero config = the built-in default show; everything runs end to end, byte-for-byte identical to the behaviour before show configs existed — the show layer is an optional asset, not a mandatory gate.
294
+
295
+ **Pipeline contract**: the framework presupposes nothing about aesthetics and is fully authoritative about pipeline interfaces. Skills whose artifacts enter the render pipeline must satisfy the corresponding contract (see [`contracts/`](./contracts/README.md), e.g. `gsap-emit v1` for HTML animation particles); a contract only constrains machine-decidable pipeline properties, and what the picture looks like is always yours.
296
+
297
+ ---
298
+
299
+ ## Configuration
300
+
301
+ `gtrk init` writes config to `~/.gitruck/config.json` (a unified user-level directory — config, caches, ffmpeg and show configs all live under `~/.gitruck/`). Resolution order: **environment variables / `.env` > persisted `init` config > default base URL**.
302
+
303
+ | Item | Source | Notes |
304
+ |---|---|---|
305
+ | `GITRUCK_API_KEY` | env / init | The **bare value** of the `Authorization` header (not a Bearer token) |
306
+ | `GITRUCK_API_BASE` | env / init | API base URL, defaults to `https://api.ai-mcn.tv:10000` |
307
+ | Jianying draft folder | init / auto-detect / `--jianying-draft-dir` | Determines where Jianying drafts land and whether they open directly |
308
+ | `defaultColumn` | hand-written in config.json | Default show config id (used by `gtrk split` when `--column` is omitted; if that is also missing, the built-in default show) |
309
+ | Show config | `~/.gitruck/columns/<id>.json` | One file per show; generated and registered by `/gtrk-style-maker`, or hand-written |
310
+
311
+ Non-interactive configuration (scripts / CI):
312
+
313
+ ```bash
314
+ gtrk init --api-key <KEY> --jianying-draft-dir auto -y
315
+ ```
316
+
317
+ Run `gtrk doctor` any time for a self-check:
318
+
319
+ ```
320
+ 运行时:node v24.x
321
+ CLI 版本:v0.3.0(已是最新)
322
+ API Key:已配(gc_xxx…)
323
+ 云端连通 + 鉴权:可达,鉴权通过
324
+ ✅ 剪映草稿目录:C:\Users\…\com.lveditor.draft
325
+ ```
326
+
327
+ ---
328
+
329
+ ## Command reference
330
+
331
+ ### `gtrk transcript <local video|voice-over audio>`
332
+
333
+ Turns a local video or voice-over audio file into a multi-level Markdown transcript. It accepts local file paths only: video is extracted — and audio input transcoded — to 16 kHz mono audio on your machine, and only that derivative is uploaded. The original file is never uploaded, and URLs or platform video downloads are not supported.
334
+
335
+ ```bash
336
+ gtrk transcript "D:/素材/采访视频.mp4"
337
+ gtrk transcript "D:/素材/采访视频.mp4" --lang zh-CN --out "D:/文字稿/采访.md" --json
338
+ ```
339
+
340
+ By default it produces only `D:/素材/采访视频-transcript.md`, whose structure is fixed:
341
+
342
+ 1. `## 总结` (Summary): the CLI marks it as pending, and `/gtrk-transcript` drives the agent to read the full text, generate it and write it back;
343
+ 2. `## 文字记录` (Transcript record): readable paragraphs each starting with `[00:01:23]`;
344
+ 3. `## 纯文本` (Plain text): the complete recognized text, easy to copy in one go.
345
+
346
+ Live pricing is queried from the website's price table under `asr` before the run; neither the CLI nor the docs store price numbers. With `--json`, stdout contains only `{ok,taskId,fileId,output,transcriptJson,summaryPending}`, where `output` points at that single Markdown file; `summaryPending:true` means `/gtrk-transcript` still needs the agent to write the semantic summary and replace the pending marker in place — the deliverable remains the same single file.
347
+
348
+ > With `--json` it additionally drops a sentence-timecoded `<name>-transcript.json` next to the source file (`utterances[]{id,text,st,ed}` + `material_id` + `text_hash` + `duration`, field-for-field aligned with the transcript structure `gtrk split` consumes), which the `gtrk project init --transcript` fallback path can consume directly. **Do not re-run ASR here on TTS-synthesized voice-overs** — `gtrk project init --tts-task` fetches the server-side sentence timecodes directly, zero ASR and zero extra billing.
349
+
350
+ ### `gtrk oralcut <raw>`
351
+
352
+ | Parameter | Purpose | Default |
353
+ |---|---|---|
354
+ | `-s, --script <file>` | Script txt (cutting against a script is more accurate) | Looks for a `.txt` next to the raw file; otherwise reconstructs the script automatically |
355
+ | `-p, --preset <p>` | Pacing `steady`\|`concise`\|`compact` (loose → tight) | `concise` |
356
+ | `-o, --out <dir>` | Custom output folder | `<raw-name>-video-project-<timestamp>` |
357
+ | `-f, --formats <list>` | Comma-separated list of the three formats | `gtrk,jianying,xml` |
358
+ | `--jianying-draft-dir <dir>` | Jianying draft root (or `auto`) | Reads the init config / auto-detects |
359
+ | `--reupload` | Force re-upload, ignoring the upload cache | off |
360
+ | `--no-open` | Do not open the output folder when done | **opens automatically by default** |
361
+ | `--json` | Machine-readable: stdout carries only the result JSON (for agents / scripts) | off |
362
+
363
+ `--json` output (a single stdout line on success): `{ ok, outDir, files:{gtrk,jianying,xml}, jianyingDraftPath, rendered, report, errors, taskId, fileId }`; on failure the process exits non-zero, errors go to stderr, and stdout carries no JSON.
364
+
365
+ > Every run **always writes a `result.json` into the output folder** (regardless of `--json`), and once submission succeeds it also drops a `task.json` breadcrumb. Even if stdout is lost or the run crashes midway, the report and `taskId` are on disk, and `oralcut-result` below can fetch everything back in seconds without re-running the cloud job.
366
+
367
+ ### `gtrk oralcut-result <taskId>`
368
+
369
+ Fetches the report and the three project formats of an **already completed** task by `task_id` (with optional local rendering), **skipping preprocessing / upload / submission / polling** — use it when the report is lost or you want to pull the artifacts again on another machine, without re-running the cloud job.
370
+
371
+ | Parameter | Purpose | Default |
372
+ |---|---|---|
373
+ | `-o, --out <dir>` | Output folder | `<cwd>/<taskId>-video-project-<timestamp>` |
374
+ | `--render` | Additionally render locally (requires the raw file still at the path embedded in gtrk, plus ffmpeg) | off |
375
+ | `--jianying-draft-dir <dir>` | Jianying draft root (or `auto`) | Reads the init config / auto-detects |
376
+ | `--no-open` / `--json` | Same as `oralcut` | — |
377
+
378
+ > Fetching results requires the **same account's** API key that submitted the task (a different account or a deleted task returns `TASK_NOT_FOUND`). The report is stored with the task record and stays available long-term; the underlying artifact files are cleaned up after roughly **60 days**, after which the report is still retrievable but artifact downloads 404 (the command tells you and still writes the report to disk).
379
+
380
+ ### `gtrk split [split doc]` — visual split dispatcher
381
+
382
+ Finished cut × transcript projection → beat storyboard. **No positional argument = export the projection view** (projects the current `.gtrk` timeline × transcript into a beat view for splitting/proofreading, without writing back); **with a split doc = validate and land it** (validates the doc's machine contract → projects beat timecodes → atomically writes back `struct_meta.split` and produces the `split/dispatch.json` dispatch list, driving the A_ROLL / MG / AI_DRAMA / FILM_BROLL lanes). Timecodes always belong to the CLI (a split doc only describes "which span does what" and never carries timecodes).
383
+
384
+ | Parameter | Purpose | Default |
385
+ |---|---|---|
386
+ | `--project <dir>` | The oralcut output folder (locates `gtrk/project.gtrk` and `transcript/transcript.json` automatically) | |
387
+ | `--gtrk <path>` / `--transcript <path>` | Explicit project / transcript paths (fallback for non-standard layouts) | Derived from `--project` |
388
+ | `--column <id>` | Show config id (validates lane / category / produces against your show's vocabulary) | config `defaultColumn` → built-in default show |
389
+ | `--md` | Also render the human-readable `split/visual-split.md` when landing (rendered one-way from the JSON) | off |
390
+ | `--words` | Attach word-level detail in view mode | sentence level only |
391
+ | `--json` | Machine-readable: stdout carries only the result JSON | off |
392
+
393
+ > The landed `dispatch.json` has three queues feeding downstream consumers: `mg` (MG particles) → the `gtrk mg` command, `film_broll` → the `gtrk matrix` command, `ai_drama` → the `/gtrk-ai-drama` skill (which emits four-part description docs in Chinese/English blocks; pure authoring, no command). The companion skill `/gtrk-splitter` produces the split doc.
394
+ >
395
+ > **Dispatch entries carry their own `span:{from,to}`** (the utterance range that entry covers; `overlay` aux entries carry **their own** span, which may be a sub-range of the main beat's). **`track_st/track_ed` are a snapshot taken at projection time** — `gtrk mg` / `gtrk matrix` **re-project on the spot** when consuming them (see below), so after editing the talking-head track you do **not** need to re-run `gtrk split`; only a change to the split doc itself requires that.
396
+
397
+ ### `gtrk patch <move|trim|split|set>` — element-level editing (the only way to edit a project)
398
+
399
+ Edit the timecode or parameters of a single clip / gap / particle. **Agents must not hand-edit `.gtrk` JSON**
400
+ a clip carries **two parallel timecode representations** (`clip_st`+`clip_ed` and `clip_st`+`duration`).
401
+ Changing one without the other is a **silent failure**: the desktop client reads `clip_ed` first while the
402
+ backend does not strictly validate it, so nothing errors out yet the render uses a stale out-point.
403
+ This command handles identity synchronisation + frame alignment + a whole-file check before writing.
404
+
405
+ ```bash
406
+ gtrk patch move --project <dir> --clip c2 --to 5.0
407
+ gtrk patch trim --project <dir> --clip c2 --out -1s
408
+ gtrk patch split --project <dir> --clip c2 --cut 5.5
409
+ gtrk patch set --project <dir> --track audio:1 --at 3.0 --volume 0.5
410
+ ```
411
+
412
+ | Flag | Purpose | Default |
413
+ |---|---|---|
414
+ | `--project <dir>` / `--gtrk <path>` | Project dir (auto-locates `gtrk/project.gtrk`) or an explicit path | — |
415
+ | `--clip <clip_id>` | Address by id. A video/audio **mirror pair** counts as one editing unit | — |
416
+ | `--track <kind:idx> --at <sec>` | Address by position (`track_st ≤ at < track_ed`). Mutually exclusive with `--clip` | — |
417
+ | `--to <sec\|Nf>` | Target position for `move` | — |
418
+ | `--in` / `--out` / `--set-in` / `--set-out` / `--slip` | The five `trim` semantics (first two relative, next two absolute, `--slip` shifts only the source window) | — |
419
+ | `--cut <sec\|Nf>` | Cut point for `split`. ⚠️ Distinct from the addressing flag `--at` | — |
420
+ | `--muted` / `--volume <gain>` / `--opaque` | Element-level parameters for `set` (`--volume` is linear gain, not dB) | — |
421
+ | `--total <sec\|Nf\|max>` | Top-level duration for `set` (project-scoped op, mutually exclusive with element addressing) | |
422
+ | `--ops <file\|->` | Batch transaction: read once, compute all, validate all, write once; any failure writes **nothing** | off |
423
+ | `--dry-run` | Compute and validate only, do not write | off |
424
+ | `--json` | Machine-readable receipt on stdout (human logs go to stderr) | off |
425
+
426
+ > Time literals: seconds (`3.5` / `3.5s`) or frames (`105f`); relative values take a sign (`-1s`).
427
+ >
428
+ > The receipt carries `ops[].resolved`, a locator triple `{track, clip_id, track_st}` — use it on the next
429
+ > round to confirm you are still pointing at the same element.
430
+ > `preexisting[]` lists invariant problems that were **already in the file** (not caused by this run, not
431
+ > blocking); violations caused by this run mean **zero writes and a non-zero exit**.
432
+ >
433
+ > ⚠️ A gap cannot be addressed with `--clip ""`: the contract lets multiple gaps share that value, so it is
434
+ > not an address. Use `--track/--at` instead.
435
+
436
+ ### `gtrk matrix` — B-roll retrieval + candidate track laying
437
+
438
+ **No positional argument = consume the dispatch**: reads the `film_broll` queue from `split/dispatch.json` → dual-endpoint retrieval → produces the candidate list `split/broll-plan.json`, downloads preview proxies, and lays N candidate tracks in the project (open it in opencut and toggle track visibility to compare and choose). **`matrix search "<query>"` = a one-off ad-hoc search** (independent of any dispatch). **`matrix fetch <clip_id...>` = pull raw footage during the fine cut** (project-independent; see below).
439
+
440
+ | Parameter | Purpose | Default |
441
+ |---|---|---|
442
+ | `--project <dir>` | The oralcut output folder (locates `split/dispatch.json` and the artifact destination) | |
443
+ | `--dispatch <path>` | Explicit `dispatch.json` path | Derived from `--project` |
444
+ | `--column <id>` | Show config id (uses your show's B-roll retrieval preferences: tags / material_class / facets) | config `defaultColumn` → built-in default show |
445
+ | `--lay <n>` | How many candidate tracks to lay (`0` = produce the plan only, lay nothing) | `1` |
446
+ | `--top-k <n>` | Candidate cap per query (overrides the dispatch's shots; server cap is 50) | dispatch value |
447
+ | `--material-class <c>` | Material type `real_shot` \| `concept` (matrix-member endpoint only; overrides the show policy) | show policy |
448
+ | `--score-floor <f>` | Fill-confidence floor: segments scoring below this are not used and the slot stays empty — empty spots **expose the black bed track** (laid by default; only `--no-black-bed` exposes the main track instead). Raising it shrinks the candidate pool, and a span that cannot be filled at all becomes pure black over the talking-head, so check the hole warnings after adjusting | `0.2` |
449
+ | `--no-black-bed` | Do not lay the solid black bed track (one is laid by default) | laid by default |
450
+ | `--force-relay` | Strip and re-lay even when you have already edited a candidate track in the client (by default it refuses and keeps that track) **this deletes the `broll-raw-*` material registrations of confirmed source clips, orphaning those files on disk** | off |
451
+ | `--out <file>` | Write ad-hoc results to a file; for `matrix fetch`, the raw-footage output directory (never the Jianying draft folder) | stdout / `./matrix-fetch/` |
452
+ | `--arrange <m>` | **B-roll arrangement route** **picked automatically by material source; you normally do not pass it**: your own local footage `cloud` (arranged in the cloud, billed by **arrangement volume**, with an estimate and a confirmation prompt first; `--yes` skips). Material from the asset matrix → `local` (arranged on your machine, not billed, unchanged byte for byte). `shadow` is an observation mode: your machine lays as usual while the cloud runs the same arrangement for comparison only. ⚠️ On the local-footage route `--arrange local` is not accepted (passing it is a parameter error), and if the cloud cannot deliver a result the command **fails outright** instead of quietly switching to a different algorithm. It is **not a way to save credits** either asset-matrix material is billed for search. Both routes cost something; they just cost it at different steps | picked by material source |
453
+ | `--arrange-qc` | **Arrangement-time QC** (off by default): before anything is laid, check each beat's anchor sentence for whether the picture actually shows what the script says; if not, swap candidates and re-arrange, at most 2 rounds, then deliver and report honestly which lines still do not match. Zero rendering throughout — it replaces the "lay → render → look → re-lay → render again" loop. ⚠️ Judging goes through the material-understanding endpoint and is **billed per frame** (1 frame per anchor sentence per round); an estimate and a confirmation prompt come first (`--yes` skips). Orthogonal to `--arrange`: works on both the local and cloud routes | off |
454
+ | `--arrange-cost-cap <n>` | Hard cap on arrangement volume for a single cloud run: over the cap the server **refuses up front** — zero execution, zero charge (it does not cut off midway). Only meaningful with `--arrange shadow\|cloud` | uncapped |
455
+
456
+ **`matrix fetch <clip_id...>` (pull raw footage during the fine cut, project-independent)**: for materials you have **searched with billing** (hits in the grant ledger), re-signs fresh download links for free by clip_id and lands them as `<clip_id>.<ext>` — when the rough cut is already exported to Jianying and one more B-roll is needed, you can pull the raw file locally and drag it straight in without going back to the client app. The flow is always **two-step**: pick clip_ids from `matrix search` → `matrix fetch` to pull (fetch itself is free of charge, performs no search, and has no confirmation gate). **Grants are persistent**: the 24h-expiring signature is no obstacle — a clip searched three days ago still fetches fine. Ungranted items are reported one by one as "not granted" with the way out (run one billed search for that keyword to obtain the grant) and never block the rest; one batch ≤ 500. **The initial scope covers video clip raws only** (the re-sign surface for image/audio materials is not open yet; such ids land in missing with a hint). Outputs never enter `.gtrk` and never land in the Jianying draft folder; material added inside Jianying does not flow back into the project (export is one-way).
457
+ | `--json` | Machine-readable: stdout carries only the result JSON | off |
458
+
459
+ > **Beat windows are re-projected on the spot**: in dispatch-consumption mode, **before the first cloud retrieval**, each beat's `[track_st, track_ed]` is recomputed from "`transcript` × the current `.gtrk`", and retrieval, `broll-plan.json` and track laying all use the recomputed values (`--lay 0` obeys the same rule; ad-hoc `search` is unaffected). The timecodes in `dispatch.json` are only a **projection-time snapshot**, used as a fallback solely when re-projection is impossible **so after editing the talking-head track you can run this command directly without re-running `gtrk split`**. `--json` always emits `reprojection:{mode,degraded,reason?,drifted,max_offset,shrunk,dropped}`; beats with **zero surviving span** after re-projection are skipped (no retrieval quota is burned on them and nothing is laid). If re-projection is impossible (missing transcript / project not found / no talking-head material on the main track) → it **degrades to the snapshot with a warning and a `--json` marker**, while retrieval and the plan still complete instead of hard-failing; behaviour for non-v1 projects is unchanged (the plan lands first, then the version gate exits non-zero).
460
+ >
461
+ > Candidates' `preview_url`/`cover_url` **are unsigned and never expire** (once the local proxy is on disk it is always reused); what carries a signature and expires in roughly 24 h is the **source `url`**, re-signed by the client's "confirm source clip" flow **you do not need to re-run this command just to re-sign**.
462
+ >
463
+ > **Re-running strips and re-lays, but never touches tracks you edited**: candidate tracks are identified by "material prefix + last round's registration fingerprint", no longer by track number (saving in the client renumbers all overlay tracks). Once a candidate track is judged "edited by you" (a clip was changed, or you confirmed the source clip in the client so the material became `broll-raw-*`), this run **lays nothing at all**: no track is stripped, no track is appended, `.gtrk` is byte-for-byte unchanged, `broll-plan.json` is still produced, and the command reports "which track / what evidence / what to do next" and exits non-zero (`--json` emits `{ok:false, refused:[…]}`). Add `--force-relay` to force a re-lay.
464
+ >
465
+ > **Material-on-disk self-check**: after writing back the project it verifies that every `materials[].path` really is on disk (**read-only, reports without touching anything**). Relative paths are always resolved against the **directory containing the `.gtrk` file** (`<output>/gtrk/`). `--json` emits `integrity:{ checked, counts, dangling:[…], danglingReferenced, danglingOrphan, external:[…], noPathIds:[…] }` — `dangling` is the complete list of **broken references** among project-owned materials (registered but missing on disk), each flagged with **whether the timeline references it** and where (a referenced one means that span has no media to show, far worse than an orphan); missing absolute paths are counted separately as `external` (an unmounted external drive looks like this too, so it does not pollute the main verdict); http(s) materials are only counted and **no network requests are made**. **This informs, it does not block**: broken references do not change `ok`, do not change the exit code, and no material entry or file is deleted. They are usually historical residue (e.g. an interrupted "confirm source clip" download); the fix is to re-confirm the source clip in the client or delete that clip. Runs that never wrote back (`--lay 0` / refused / missing project) **emit no `integrity` field** — absence means "not checked this time", not "checked and clean".
466
+ >
467
+ > **The solid black bed track**: by default a solid black track is laid beneath all candidate tracks and above the talking-head main track (`struct_meta.broll.black_track` records its `track_index`), covering the full landed beat envelope so that during B-roll (including the empty spots on candidate tracks) the talking-head picture underneath is not exposed. **The cost is "black holes"**: wherever candidate tracks are not filled, pure black covers the talking-head, and track laying computes exactly that — `--json` always emits `lay.blackBedHoleSec` plus per-span `lay.blackBedHoles`, and a non-fatal warning is added when a single span is ≥ 3 s or a single beat's ratio is ≥ 15 % (it does not change the exit code or block laying). Use it to adjust `--score-floor`, switch to `--no-black-bed`, or patch by hand in the client. The bytes land at `assets/builtin/solid-000000-<W>x<H>.png`, sharing an id namespace with the client's built-in solid material and reused idempotently. Do not delete it by accident when removing candidate tracks; to swap footage, drag onto a candidate track's clip and **not onto the black bed** — since client 0.2.10 (force-updated release on 2026-07-31) **dropping onto the black bed is rejected outright with a message**. On clients older than 0.2.10 (force update not yet pulled) the old behaviour silently creates a new video track and inserts there; if it lands in the lower half you cannot see it in the preview at all (one `Ctrl+Z` undoes the whole thing) — restart the client first to pick up the force update. If you do not want the black bed, re-run with `--no-black-bed` and it is stripped clean.
468
+
469
+ **Local-footage mode (`matrix index` / `--local`)**: footage does not have to live in the cloud library — retrieve and lay tracks straight from your local footage folders (video and images mixed):
470
+
471
+ ```bash
472
+ gtrk matrix index --dirs <folder1,folder2> # ① build a slice-free index: content-fingerprint incremental, resumable; renames/moves are not recomputed
473
+ gtrk matrix --local --dirs <folder1,folder2> --project <dir> # local retrieval + track laying (--lay 0 = plan only, no laying)
474
+ gtrk matrix lay --project <dir> [--plan <path>] # consume the (edited) plan and lay tracks, zero retrieval cost
475
+ ```
476
+
477
+ - **Your footage never leaves your machine**: only 512px sampled frames are sent to Gitruck Cloud's own embed endpoint for vectorization, discarded on arrival; results reference your local originals by absolute path (no downloads, no proxies). Indexing is metered by frames actually sampled (pre-held before the run, settled to actual usage afterwards); text-side retrieval costs zero credits.
478
+ - **Images are first-class**: images are indexed, retrievable and layable; when selected, an image goes through cloud `image_move` and lands as a 5-second camera-move video **the image itself does go to the cloud** (2 credits per image, summarized for confirmation before laying; same image + same params is reused forever, never re-billed). Zero images to the cloud `--no-image-broll`.
479
+ - **No material reuse**: within one laying round each material unit is used once globally (local video per scene, images per file); when candidates run dry, slots stay empty rather than repeat; `--dedup-scope material` tightens to file level.
480
+ - **Projects containing local footage cannot cloud-render**: submission is rejected (`local_broll_cloud_render_rejected`) produce locally in the desktop client or via `gtrk render`.
481
+ - **Optional atoms**: `matrix describe --plan <path> [--top-k N]` / `--materials <a,b>` understands candidates on demand (VLM description / tags / quality mark / watermark·subtitle·black-border·blur signals; 1 credit per frame, results injected into the plan and cached locally, cache hits are free, >20 frames triggers a confirmation guard); `--source-window <start,end>` filters by source-time window (only with `--local`; the film-commentary pattern "segment N of the narration gets footage from around segment N of the film"); `matrix lay --mark-weight <0..1>` blends describe's quality mark into candidate ranking (fused score = sim×(1-w)+(mark/100)×w; reorders only, never changes admission; candidates without a cached mark are treated as neutral).
482
+ - **Index knobs and score scale**: `--scene-threshold` tunes scene-split granularity, `--stability-threshold` collapses static-camera scenes to fewer sampled frames, `--rebuild` forces a rebuild (describe caches are kept); the index is not portable across machines (keys are absolute paths just re-run `index` on the new machine). Local score scale differs from the cloud's (a perfect hit can score as low as ~0.25), so do not raise `--score-floor` on cloud instincts.
483
+
484
+ Orchestration recipes (pure matching / describe-then-lay / time-window / footage-first scripting / three-layer stacking) and the plan-editing contract live in the bundled skill `/gtrk-matrix`.
485
+
486
+ ### `gtrk mg` MG motion-graphics particles (lay / lint / status / render)
487
+
488
+ Consumes the `dispatch.mg` dispatch landed by `gtrk split`, laying html-particle assets produced by **your show's MG skill** into the `.gtrk` project's `beat_track`. Four modes are dispatched by the first positional word: **no argument = lay**, `mg lint <file>` = single-file validation, `mg status` = orchestration dashboard, `mg render <file>` = standalone particle cloud render (project-independent; the fine-cut supplement channel). The old name `gtrk rrv` remains a deprecated alias (it prints a notice; prefer `gtrk mg`).
489
+
490
+ | Parameter | Purpose | Default |
491
+ |---|---|---|
492
+ | `--project <dir>` | The oralcut / split output folder (locates `split/dispatch.json` and the `.gtrk` project) | — |
493
+ | `--dispatch <path>` | Explicit `dispatch.json` path (fallback for non-standard layouts) | Derived from `--project` |
494
+ | `--only <beat>` | Run a single beat only (takes a **beat id** such as `B12`, not a `composition_id`; the main particle and its `-aux<n>` overlays are selected together). **True incremental merge**: only the matched particles are re-laid, and every other already-laid particle on the track (including your manual tweaks) is preserved as is | all |
495
+ | `--lint-only` | Lint only; lay nothing and write nothing back | off |
496
+ | `--replace-all` | Explicitly authorize a **full track reset**: no incremental preservation, the whole track is stripped and re-laid **this deletes every other already-laid particle on the track** | off |
497
+ | `--duration <sec>` | **Required in render mode**: the explicit duration anchor (seconds) — standalone mode has no slot envelope, so this value is at once the lint envelope, the output duration and the billed duration | |
498
+ | `--format <fmt>` | Render-mode output format: `qtrle` only for now (Jianying-readable transparent MOV; `webm` is explicitly refused — Jianying cannot read VP8-alpha) | `qtrle` |
499
+ | `--out <dir>` | Render-mode output directory (never writes into the Jianying draft folder dragging into Jianying is your move) | `./mg-render/<composition_id>/` |
500
+ | `--yes` | Render mode: skip the billing-estimate confirmation | off |
501
+ | `--json` | Machine-readable: human logs go to stderr, stdout carries only the result JSON | off |
502
+
503
+ - **Laying** (`gtrk mg --project <dir>`): reads `dispatch.mg` for each beat takes the source particle from `<project>/mg/<composition_id>.html` lints lays it into `beat_track` and atomically writes `struct_meta.mg` back into `.gtrk` (self-produced tracks are registered idempotently in `lay_tracks`; a re-lay strips the previous self-produced items before appending, and user-added tracks are never touched). Whether a particle is a "transparent overlay" or a "full-screen bed" is decided by `opaque`, inferred from the particle HTML's root `background`. Beats with a missing HTML file or a failed lint are counted in `skipped` and do not block the rest.
504
+ - **The stripping surface ≠ "what gets laid this run", and ≠ "every registered track"**: `--only <beat>` **strips only the matched particles** (true incremental merge) — every other already-laid particle's clip / material / registration entry is **preserved as is**, together with any manual tweaks you made in opencut (what is preserved is the existing clip itself, not a rebuild from the registration, so transparency `opaque` is not lost); those preserved entries are **not re-linted and their source HTML is not re-copied** (the project is self-contained, so deleting files under `<project>/mg/` does not matter). A full re-lay is still "strip clean, then rebuild the whole track", with **one exception**: particles that are in this dispatch but failed to land (missing HTML / failed lint / zero surviving span after re-projection) keep their previous round's clip on the track (a broken new one must not destroy the working old one); conversely, already-laid entries **no longer present in the dispatch** are still stripped (a plan change ≠ something broke). To strip every other already-laid particle too, authorize it explicitly with `--replace-all`.
505
+ - **The material table does not accumulate**: materials are stripped by "**self-produced identity × zero references**" (self-produced = a `mg-`/`rrv-` prefix **or** living under the CLI-exclusive `assets/mg/` with a filename in the self-produced registry), and **it deliberately does not trust the client-rewritable `html_material` prefix** — so re-laying after editing the project in opencut still strips old materials, the `mg-` material count **always equals the number of particles on the track**, and historical duplicate/orphan entries are cleaned up along the way. **Non-self-produced materials are never touched** (`broll-*` / `ex-solid-*` / anything you added, even with zero references); self-produced materials still referenced by a surviving clip are also not stripped (it will never strip a clip into a broken reference); the html copies under `assets/mg/` on disk are never deleted.
506
+ - **"Nothing matched" is not a clear-everything instruction**: when `--only` matches nothing, `dispatch.mg` is empty/missing, or every entry in this run was skipped, **while the track already has laid particles**, the write-back is refused (that is a signal that the dispatch or the selector is broken). Add `--replace-all` if you really mean to clear it. A first-time lay (no existing laid entries on the track) is exempt and completes normally, reporting `laid=0`.
507
+ - **Slot windows are re-projected on the spot**: before laying and linting, each queue entry's `[track_st, track_ed]` is recomputed from "`transcript` × the current `.gtrk`", and thereafter the lint slot envelope (house rule ⑦) and the laid clip duration both follow the recomputed values (`--only` obeys the same rule; aux particles re-project against **their own** span and are not conflated with the main beat window). The timecodes in `dispatch.mg` are only a **projection-time snapshot**, used as a fallback solely when re-projection is impossible **after editing the talking-head track you can lay directly without re-running `gtrk split`**. `--json` always emits `reprojection:{mode,degraded,reason?,drifted,max_offset,shrunk,dropped}` (including under `--lint-only`). Entries with **zero surviving span** after re-projection are skipped and counted in `skipped` (no HTML is copied and nothing is laid back from the snapshot); if re-projection is impossible (missing transcript / project not found / no talking-head material on the main track) → it degrades to the snapshot with a warning and a `--json` marker, and the exit code is unchanged; behaviour for **non-v1** projects is unchanged (the laying path's version gate exits non-zero, while `--lint-only` still produces its report). A successful lay appends this run's timecode provenance (`timecode_source` / `reprojected_at`) into `struct_meta.mg`.
508
+ - **lint** (`gtrk mg lint <particle.html> [--dispatch <path>]`): a purely local static check of the machine-decidable subset of the house rules for a particle HTML (wrapped in `<template>`, `data-composition-id` + 1920×1080, `gsap.timeline({ paused: true })`, registration in `window.__timelines`, no `Math.random` / `Date.now`, self-contained with no relative external links, root `background` consistent with `opaque`, …); when `--dispatch` is given it also checks that the `composition_id` matches the dispatch. Any fatal item exits non-zero and reports every reason.
509
+ - **Expected-id consistency** (`1-cid-expect`, **fatal**): the `data-composition-id` inside the HTML must equal the expected id (when laying, the dispatch entry's `composition_id`; for `mg lint`, the filename but only when it matches the dispatch or looks like `…-B<digits>[-aux<n>]`, so a renamed copy such as `./tmp.html` is not compared). This guards against "copying `<id>.html`, renaming the file and forgetting the id inside" — laying would write a clip/material named after the file while the file registers a different `__timelines` key and fights the same-named particle over the same style scope.
510
+ - **House rule ⑦, timeline length estimation** (`7-fill-slot` / `7-no-estimate` / `7-infinite-repeat`, **always non-fatal, never blocks laying**): when the slot envelope is known (per particle when laying; for `mg lint --dispatch` when it matches a dispatch entry) it computes a **static lower bound** on the GSAP timeline degrading call by call, counting whatever it can parse (`duration×(repeat+1) + repeatDelay×repeat`, with `yoyo` adding no time), while calls with expression positions or non-literal durations are **skipped and not counted** (ignoring some calls still yields a valid lower bound). Estimate < envelope warning; nothing computable at all an explicit notice that "length could not be estimated statically, house rule was not verified, and it must be accepted against the real engine's seek" (**never silent**: "could not compute" and "computed and passed" are distinguishable in the output); containing `repeat:-1` a warning that "an infinite loop makes the total length Infinity, so house rule cannot be verified statically; please use a finite repeat computed from the slot". The real criterion is always the render engine frame by frame; this item is only a reminder layer.
511
+ - **House rule ⑧, repeated-primitive merging** (`8-primitive-merge`, **always non-fatal, never blocks laying**): identifies mergeable batches of `line` / `rect` / `path` / `polyline` / `polygon` that are "created inside a loop, or by a named factory called in a loop; landing under the same parent node; and not driven by per-element animation". Only batches whose purely numeric loop trip counts sum to **≥ 8** under the same parent are reported; when bounds involve `.length` or named constants and cannot be computed it still reports "count unknown" without constant folding; elements with per-element `gsap.set` / tweens, or used as a tween's first argument, are excluded. This item only points out "there is a batch of repeated primitives here that can be merged **losslessly**, pixel-identical after merging" — it is **not a risk verdict**: a hit does not mean the particle will reproduce a defect, and a miss does not mean it is safe. The real criterion remains sampling frames from a real render.
512
+ - **Callback and seek semantics** (`x-callback-driven` / `x-engine-api-override` / `x-raf-interval`, **always non-fatal, never blocks laying**): aligned with the same-named section of the contract (added 2026-07-26). GSAP `seek(t)` suppresses callbacks by default tweened properties still interpolate, but DOM writes inside `onUpdate` do not run, and the failure mode is **the picture freezing at its initial state rather than going black**. The contract places the guarantee on the **engine side** (fixing a frame MUST use `seek(t,false)` / `time(t)` / `progress(p)`), so a particle **driving its picture from callbacks is a compliant style**; these three lint items are merely **sentinels**: `x-callback-driven` = callbacks write the DOM with no seek fallback anywhere (it stays silent when a fallback exists, to avoid nagging); `x-engine-api-override` = the particle overrides `tl.seek` at runtime or replaces `__timelines[…]` with a wrapper object (which would override the engine's explicit `seek(t,true)` and stops working the moment the engine switches to `time()`/`progress()`; a transitional state); `x-raf-interval` = it contains `requestAnimationFrame(` / `setInterval(` (its own clock is not driven by seek, i.e. frozen). All three MUST NOT be fatal "driving the picture from callbacks" is not a violation.
513
+ - **status** (`gtrk mg status --project <dir>`): summarizes the MG pipeline — total beats in `dispatch.mg` / how many source HTML files exist / how many are laid into `.gtrk`, annotating each beat (missing HTML / produced but not laid / laid).
514
+ - **render** (`gtrk mg render <particle.html> --duration <sec> [--out <dir>] [--yes]`): renders a single particle in the cloud, **independent of any project**, into a Jianying-readable qtrle transparent alpha MOV (the fine-cut supplement channel — when the rough cut is already exported to Jianying and one more motion graphic is needed, you can add it without going back to the client app). The chain = lint upfront (envelope = `--duration`; any fatal item is blocked locally, zero submission, zero billing) → **billing-estimate confirmation** (live price lookup; the CLI has no local HTML render engine, so the cloud billed task is the only path for standalone particles; `--yes` skips the prompt) → inline submission to the cloud → `<composition_id>.mov` landed with `task.json`/`result.json` breadcrumbs (recoverable by task_id after a crash). **Scope**: qtrle only for now (`--format webm` is explicitly refused — Jianying cannot read VP8-alpha), 1920×1080 particles only (the contract has no portrait/odd-canvas opening), and `--duration` is required. The output never enters `.gtrk` and never lands in the Jianying draft folder; qtrle is lossless and relatively large, suited to seconds-long particles. Note it shares a word with `gtrk render` (full-video rendering) but is a different thing.
515
+
516
+ `--json` output: `{ ok, mode:"lay"|"lint"|"status", }` (each mode carries its own fields, e.g. `laid` / `skipped` when laying, per-beat status for `status`). Laying mode additionally carries **`track_total`** (how many laid particles currently exist on the track), **`kept`** / **`kept_ids`** (how many are **left over from the previous round** and not re-laid this time, plus their `composition_id` list) and **`removed`** (how many old self-produced particles were stripped this run) — `laid` (this run), `track_total` (total on the track) and `kept` (left over) **must be read together**, and `track_total = laid + kept` always holds. Reading `laid` alone makes "lay 1, strip 20" look identical to "patch in 1", and reading only the first two hides the cost that "a few particles on the track are not from this round" (`kept_ids` and `skipped` overlap: something that failed to land this round is still there from the previous one). When not fully green it also carries a machine-readable **`reason`**: `skipped` (some were not laid) / `empty_queue` (**write-back refused**, the project was not modified, with `refused:true` and `blocked[]`) / `no_project` (project missing, nothing laid). Runs that actually wrote back also carry **`integrity`** (the material-on-disk self-check, identical in name and shape to `gtrk matrix`; see the previous section).
517
+
518
+ > **Exit codes**: an `ok:false` from laying or `--lint-only` **always comes with a non-zero exit** (including the ordinary mid-loop case of "some beats were skipped"). Agents should not read non-zero as "the command crashed" — judge by `reason` / `skipped`.
519
+
520
+ > **Aux overlay particles**: if `gtrk split` dispatched an `overlay` particle in some beat's `aux_layers`, it derives a `<beat>-aux<n>` composition entry into `dispatch.mg` — `gtrk mg` lays it too, giving you "a main visual on the base track plus a transparent conceptual diagram stacked on the same span".
521
+ > **Dual-read compatibility**: `dispatch.mg` (also reads the old `rrv_mg`), the source directory `mg/` (also reads the old `rrv/`), the material prefix `mg-` (also reads the old `rrv-`) projects created before the de-branding need zero migration.
522
+
523
+ ### `gtrk project init` / `gtrk audio lay` — audio-first project atoms (voice-over first)
524
+
525
+ Project entry points that start from **a voice-over** instead of a talking-head raw: with the voice-over in hand (TTS-synthesized or self-recorded), `project init` builds the `.gtrk` project, and `gtrk split --project` continues the production pipeline as usual; `audio lay` adds an audio track (BGM/score) to any project.
526
+
527
+ | Command | What it does |
528
+ |---|---|
529
+ | `gtrk project init --tts-task <task_id>` | **Main path**: references a completed `audio_tts_clone` task — the server hands over the audio and sentence timecodes directly (zero ASR, zero extra billing); the audio download lands in the project's `audio/` |
530
+ | `gtrk project init --audio <voice-over> --transcript <transcript.json>` | **Fallback path**: your own voice-over audio plus its sentence-timecoded transcript as a pair (produced by `gtrk transcript <voice-over> --json`; for TTS-synthesized voice-overs take the main path instead of re-running ASR) |
531
+ | `gtrk audio lay --project <dir> --file <bgm.mp3>` | Appends an audio track to the project; **idempotent same-source replacement** (re-running with the same source replaces instead of piling up tracks; zero-reference protection when stripping the old one); `--volume <0..1>` (default 0.3, bed volume), `--offset <ms>` sets the in-point |
532
+ | `gtrk audio lay … --beat-align` | Cloud beat analysis (`audio_music_analyze`, billed once) snaps the in-point to the nearest downbeat; without a key / on analysis failure / out of range it degrades to no alignment — the command never fails over it |
533
+
534
+ `project init` also takes `--canvas <WxH>` (default 1080x1920), `-o/--out`, `--reupload`, `--no-open` and `--json` with the same semantics as `oralcut`; with `--json` both commands emit a single-line result JSON on stdout (human logs go to stderr).
535
+
536
+ ### `gtrk tool <name> [inputs...]` the single-shot tool family
537
+
538
+ Standalone single-request capabilities, kept separate from the pipeline's lane commands (`oralcut`/`split`/`matrix`/`mg`). **A top-level command dispatched by the first positional word** (no parent/child commands): `gtrk tool <name> [inputs...]` runs a tool (multi-file image tools accept several paths, and the order is the assembly order), `gtrk tool list` lists them all. One tool = one thin descriptor (input category / payload assembly / artifact mapping / billing / availability gate), sharing a runner that performs "validate upload (fingerprint cache, auto-chunked ≥ 256 MiB) → submit → poll → stream-download to disk → `task.json`/`result.json` breadcrumbs" — adding a tool means adding one descriptor, never writing orchestration.
539
+
540
+ | Tool | Input | Output | Billing | Status |
541
+ |---|---|---|---|---|
542
+ | `image_move` | One image; optional `--motion` picks one of 26 camera moves | Camera-move video (geometry derived from the source orientation: landscape 1920×1080 / portrait 1080×1920) | Queried live before the run | Live |
543
+ | `image_matting` | One image | Transparent-background png (`--param` can request a backing plate) | Queried live before the run | Live |
544
+ | `image_blackborder_remove` | One local image | Image with black borders removed | Queried live before the run | Live |
545
+ | `image_canvas_adapt` | One local image; optional target width/height and `normal` / `rectangle` / `square` | Aspect-adapted image | Queried live before the run | Live |
546
+ | `image_purify` | One local image (only material you have the rights to process) | Image cleaned of watermarks, logos or overlays | Queried live before the run | Live |
547
+ | `video_matting` | One video (**≤ 10 minutes**, uploaded as-is with no proxy) | Transparent-background webm | Queried live before the run | Live |
548
+ | `video_blackborder_remove` | One local video | Video with black borders removed | Queried live before the run | Live |
549
+ | `video_canvas_adapt` | One local video; optional target width/height, clip range, canvas mode and audio-free output | Aspect-adapted video | Queried live before the run | Live |
550
+ | `video_stabilizer` | One local video; optional `fast` / `exp` / `turbo` | Stabilized video | Queried live before the run | Live |
551
+ | `video_vaporwave` | One local video; the filter takes an exact preset name | Vaporwave-filtered video | Queried live before the run | Live |
552
+ | `video_purify` | One local video; optional `full_screen` / `subtitle` / `custom`, `ffmpeg` / `raft` and a normalized ROI (only material you have the rights to modify) | One cleaned video | Queried live before the run | Live |
553
+ | `video_upscale` | One local video (**≤ 1 minute**); optional `2` / `3` / `4`× and `Reality` / `Anime` | One upscaled video | Queried live before the run | Live |
554
+ | `video_interpolate` | One local video; optional `2` / `3` / `4`×, with no extra one-minute limit | One frame-interpolated video | Queried live before the run | Live |
555
+ | `video_segment` | One local video; optional `--detector content\|adaptive`, `--threshold` | Shot-range structure in `result-output.json` (structured data, not a downloadable file) | Queried live before the run | Live |
556
+ | `video_ai_segment` | One local video; optional `--segment-mode scene\|shot_type\|narrative\|subject` | Semantic shot structure in `result-output.json` (structured data, not a downloadable file) | Queried live before the run | Live |
557
+ | `video_motion_cut` | One local video | Camera-move / highlight segment structure in `result-output.json` (structured data, not a downloadable file) | Queried live before the run | Live |
558
+ | `video_speaker_detect` | One local video; optional `--language`/`--max-faces-per-frame`/`--detect-body`/`--track-sample-fps` (GPU heavy) | Visible-speaker structure in `result-output.json` (the time base follows the server output) | Queried live before the run | Live |
559
+ | `video_face_track` | One local video; optional `--sample-fps`/`--max-faces`/`--min-face-ratio`/`--enable-body-match`/`--similarity-threshold`; `time_ranges` goes through `--params-json` (GPU heavy) | Person id / time span / trajectory structure in `result-output.json` (the time base follows the server output) | Queried live before the run | Live |
560
+ | `audio_tts_clone` | **No file**: one of `--text`/`--text-file` (≤ 5000 characters) plus a required `--speaker`; optional language/format/speed/segmentation/subtitles | Voice-over audio wav/mp3 (plus optional subtitles); billed by character count — the unit and unit price come from what `gtrk tool list` shows live | Queried live before the run | Live |
561
+ | `video_ai_subtitle` | One video or audio file; `--language <code>` required; optional `--translate-language`, `--need-render`, `--need-pure`, `--subtitle-type`, `--subtitle-color`. By default only locally extracted audio is uploaded (the raw file never leaves your machine) | `.ass` subtitles + optional burned-in / subtitle-stripped `.mp4` + `result-output.json` (summary + word-level timeline) | Queried live before the run | Live |
562
+ | `subtitle_translate` | One **subtitle file** `.ass` / `.srt`; **both** `--language <code>` and `--translate-language <code>` are required; optional `--output-format`, `--line-mode`, `--bilingual`, `--subtitle-type`, `--subtitle-color`, `--canvas <WxH>`. No speech recognition | Translated subtitles `.ass` or `.srt` + `result-output.json` (entry counts + degradation flags) | Queried live before the run | Live |
563
+ | `video_long2short_pro` | One long video (uploaded whole); `--language <code>` required; optional `--output-language`, `--main-topic`, `--output-size`, `--no-jump-cut`, `--duration-pref`, `--max-clip-sec`, `--split-screen`, `--split-orientation`, `--speed-factor`, `--no-camera-move`, `--no-subtitle`, `--subtitle-translate-language` | Finished clips `clip{i}.mp4` + the human-readable report `clips.md` (including polish-degradation details) + `result-output.json` | Queried live before the run | Live |
564
+ | `audio_separation` | One audio file; optional `--mode fast\|turbo` | Vocal and accompaniment audio (one or two items, depending on what is returned) | Queried live before the run | Live |
565
+ | `audio_speaker_split` | One audio file; optional `--only-struct` | Per-speaker `.wav` stems + a `spoken_list` timeline (`result-output.json`) | Queried live before the run | Live |
566
+ | `audio_stretch` | One audio file; optional `--semitones <n>`, `--speed <n>` (> 0) | Pitch/tempo-shifted audio | Queried live before the run | Live |
567
+ | `audio_noise_reduce` | One audio or video file; optional `--prop-decrease 0..1` | Denoised audio | Queried live before the run | Live |
568
+ | `audio_silence_remove` | One audio file; optional silence threshold and retained length | Silence-trimmed audio | Queried live before the run | Live |
569
+ | `piano_audio_to_midi` | One audio file | A MIDI file `.mid` | Queried live before the run | Live |
570
+ | `piano_audio_enhance` | One audio file | High-quality WAV + accompanying MIDI (two artifacts) | Queried live before the run | Live |
571
+ | `image_to_square` | One image; optional `--max-line <px>` ( 20000) | Square image | Queried live before the run | Live |
572
+ | `image_to_live` | One image | A short video of about 4 seconds `.mp4` (silent); or an Android motion photo `.jpg` plus the same clip as a companion `.mp4` | Queried live before the run | Live |
573
+ | `image_classic_template` | **Several images** + a required `--main-title`; optional subtitle/mode/ratio/quality/count/layout | Finished cover/collage (text/pic/render groups, possibly several images) | Queried live before the run | Live |
574
+ | `image_vertical_stitch` | **Several images** (order = top-to-bottom stitching order) | One vertically stitched long image | Queried live before the run | Live |
575
+ | `video_split_screen` | **2–16 video segments** (multiple positionals); the precise tier uses `--clips-json` (entries `{input:0-based index, begin_time_ms, end_time_ms, crop}`, millisecond time base); nine optional layout/aspect/audio parameters | One split-screen video (its length matches the shortest segment) | Queried live before the run | Live |
576
+ | `mad` | One material folder (3–10 videos) + optional `--bgm` | An AE master-composition project `.jsx` (AE only) | Only `--bgm` triggers a live price query | Live |
577
+
578
+ > Prices come from `gtrk tool list --json` and the anonymous live query printed to stderr before execution; this README stores no price snapshot. `video_matting` probes duration with ffprobe before uploading and rejects anything over 10 minutes outright (nothing is uploaded or submitted — trim it first).
579
+ > `mad` is the family's first **local-type "purely local tool with optional cloud extras"**: it runs without a key and triggers no billed job (technique data is delivered through a cloud manifest and cached in `~/.gitruck/mad-cache`, so **the first fetch needs the network and afterwards it runs offline**); only `--bgm` beat-syncing needs a key and triggers one cloud beat analysis. Three degradation tiers (key + beat sync / no key or bad BGM fixed tempo / cloud failure degraded) never crash. It produces only `.jsx` and supports AE only.
580
+
581
+ The seven shared video tools — black-border removal, aspect adaptation, stabilization, vaporwave, cleanup, upscaling and interpolation — accept only the server's current `video_ext`: `.mp4`, `.avi`, `.mpg`, `.mov`, `.flv`, `.mxf`, `.mpeg`, `.ogg`, `.3gp`, `.wmv`, `.h264`, `.m4v`, `.ts`; `.mkv` and `.webm` are rejected locally. Inputs must be local file paths the CLI does not download remote videos.
582
+
583
+ - `gtrk tool list [--json]` — list every tool (name/description/input/output/live price/status); `--json` emits a single-line machine-readable array (including dynamic `billingHint`/`pricing`). **Works without an API key**; prices are queried anonymously through a public endpoint, and on failure the full list is still shown with an unavailable marker.
584
+ - `gtrk tool image_move ./photo.jpg [--motion zoom_in_center] [--json]` — image to camera move; artifacts land in `photo-image_move/`. `--motion` picks the camera move explicitly (26 values: 8 pans `up_to_down`/`down_to_up`/`left_to_right`/`right_to_left` plus four diagonals, 9 zoom-in anchors `zoom_in_{up,down,left,right,left_up,right_up,left_down,right_down,center}`, 9 zoom-out anchors `zoom_out_` at the same positions); when omitted the server picks one automatically. `--param width=1080 --param height=1920` overrides the derived geometry.
585
+ - `gtrk tool image_matting ./portrait.jpg` / `gtrk tool video_matting ./clip.mp4` image/video matting.
586
+ - `gtrk tool image_blackborder_remove ./photo.jpg [--json]` — automatically crops black borders from one image.
587
+ - `gtrk tool image_canvas_adapt ./photo.jpg --canvas-width 1080 --canvas-height 1920 --canvas-type rectangle [--json]` — image aspect conversion; omitting the canvas parameters uses the server defaults. Per the actual runtime contract the canvas mode accepts only `normal`, `rectangle` and `square`, not the `fit` from older docs.
588
+ - `gtrk tool image_purify ./photo.jpg [--json]` — clean watermarks, logos or overlays from an image you have the rights to process.
589
+ - `gtrk tool video_blackborder_remove ./clip.mp4 [--json]` — automatically crops black borders from one video while keeping the original audio.
590
+ - `gtrk tool video_canvas_adapt ./clip.mp4 --canvas-width 1080 --canvas-height 1920 --canvas-type rectangle --clip-start 12 --clip-end 60 --without-audio [--json]` — video aspect conversion; `--clip-start/--clip-end` are start/end frame numbers, omitted fields use the server defaults, and the canvas mode accepts only `normal`, `rectangle`, `square`.
591
+ - `gtrk tool video_stabilizer ./clip.mp4 --stabilizer-method turbo [--json]` — video stabilization; supports `fast`, `exp` and `turbo`, where `exp` is experimental and you should check the result yourself.
592
+ - `gtrk tool video_vaporwave ./clip.mp4 --vaporwave-filter "灼熱苦夏" [--json]` — add a vaporwave filter using an exact preset name; omitting it explicitly uses `愈漸升溫`.
593
+ - `gtrk tool video_purify ./clip.mp4 --purify-scope custom --purify-method ffmpeg --purify-roi 0,0.78,1,0.2 [--json]` — clean a video you have the rights to modify; the ROI is a normalized `x,y,w,h` and is only used together with `custom`. `raft` supports videos under 20 minutes, `ffmpeg` has no such limit; restoring occluded content is not promised.
594
+ - `gtrk tool video_upscale ./clip.mp4 --upscale-times 3 --upscale-type Anime [--json]` — experimental video upscaling; input up to 60 seconds, neither side may exceed 4000 px after scaling, supports `2`, `3`, `4`× and `Reality`, `Anime`.
595
+ - `gtrk tool video_interpolate ./clip.mp4 --interpolate-multiplier 3 [--json]` — frame interpolation; supports `2`, `3`, `4`×, does not apply the one-minute limit from older docs, and neither side of the source may exceed 4000 px.
596
+ - `gtrk tool video_segment ./clip.mp4 [--detector adaptive] [--threshold 27] [--json]` — mechanical shot segmentation; produces **structured** `result-output.json` (`scene_list` with each range's start/end/duration), not a downloadable file.
597
+ - `gtrk tool video_ai_segment ./clip.mp4 [--segment-mode shot_type] [--json]` — semantic shot segmentation; produces `result-output.json` (`categories[].shots[]` with shot size, tags, descriptions and second-level timecodes).
598
+ - `gtrk tool video_motion_cut ./clip.mp4 [--json]` camera-move / highlight segments; produces `result-output.json` (`cut_points[]` with frame numbers, second-level timecodes and motion features).
599
+ - `gtrk tool video_ai_subtitle ./clip.mp4 --language zh [--translate-language en] [--need-render] [--subtitle-color 湖蓝]` — AI subtitles: `--language` is required, and it produces `.ass` subtitles + `result-output.json` (LLM summary + word-level timeline). **By default only locally extracted audio is uploaded** (the raw file never leaves your machine, and the geometry is sent along with the request); `--need-render` switches to **burning in locally with ffmpeg** (it errors out if `思源黑体 CN Bold` (Source Han Sans CN Bold) is missing rather than substituting another font); `--need-pure` needs the picture, so adding it uploads the whole video. The `subtitle_type`/`subtitle_color` enums and `content` are documented in the cloud API docs, and `--params-json '{"content":{...}}'` passes them through.
600
+ - `gtrk tool subtitle_translate ./movie.ass --language zh-CN --translate-language en-US [--bilingual] [--canvas 1080x1920]` — AI subtitle **translation**: move existing subtitles into another language; **both language parameters are required**. **The line between this and `video_ai_subtitle` is the input shape**: to recognize subtitles from audio or video use `video_ai_subtitle`; to move an existing `.ass`/`.srt` into another language use this one (no ASR re-run, and your existing proofreading is preserved). `--line-mode keep` keeps the timeline line for line with the input (so the track can directly replace the original), while the default `resegment` reads more naturally but changes line counts and timecodes. `.srt` files carry no canvas information, so **always pass `--canvas` for portrait output**, otherwise lines are wrapped for landscape and may run past the edge. Style options only apply to `ass` output; combining them with `srt` output is rejected server-side before any charge.
601
+ - `gtrk tool video_long2short_pro ./talk.mp4 --language zh-CN [--split-screen] [--speed-factor 1.1]` — long-to-short **fine cut**: finished clips in one shot, one `clip{i}.mp4` each plus the human-readable report `clips.md` (including polish-degradation details). **Division of labour with `gtrk long2short` (rough cut)**: the rough cut produces editable projects (gtrk/Jianying/Premiere), never uploads the raw file, and hands the result to a human for further editing; the fine cut produces only finished videos, uploads the whole file, and costs roughly twice as much. The deciding question: will you edit it afterwards? If yes, rough cut; if no, fine cut.
602
+ - The three above are **analysis-type tools**: their artifact is structured data in `result-output.json` (not downloadable media), so `result.json`'s `resultFile` points at it while `files` is empty and `ok=true` that is normal.
603
+ - `gtrk tool audio_separation ./song.mp3 [--mode turbo]` — vocal/accompaniment separation; low-frequency fields such as `--param need_vocals=false` can still be passed through.
604
+ - `gtrk tool audio_speaker_split ./meeting.mp3 [--only-struct]` — speaker diarization: by default it produces per-speaker `.wav` files + `result-output.json` (the `spoken_list` timeline); `--only-struct` emits the structure without cutting files.
605
+ - `gtrk tool audio_stretch ./song.mp3 [--semitones -3] [--speed 1.5]` — pitch and tempo shifting; pitch and speed are independent, and `--speed` must be > 0.
606
+ - `gtrk tool audio_noise_reduce ./interview.mp4 [--prop-decrease 0.5]` — accepts audio or video and always outputs denoised audio.
607
+ - `gtrk tool audio_silence_remove ./talk.mp3 [--min-silence-len 800] [--desired-silence-len 200]` removes over-long silences and writes only the processed audio.
608
+ - `gtrk tool piano_audio_to_midi ./piano.mp3` — transcribe piano audio into `.mid`.
609
+ - `gtrk tool piano_audio_enhance ./piano.mp3` — piano recording restoration, producing a high-quality WAV as the main artifact plus a companion MIDI.
610
+ - `gtrk tool image_to_square ./long.jpg [--max-line 8000]` — long image to square; `--max-line` defaults to 4000 and caps at 20000.
611
+ - `gtrk tool image_to_live ./photo.jpg [--output-format motion_photo]` — bring a still photo to life. By default the artifact is a silent `.mp4` video of about 4 seconds; `--output-format motion_photo` instead delivers an **Android motion photo** (a single `.jpg` with the clip embedded after the still image, so a gallery plays it on long-press), plus the same clip as a companion `.mp4`. Both formats cost the same. Compatibility: Android galleries that support the standard recognise and play it; **iOS does not** and shows a plain still image; a few Android models may only ever show the still.
612
+ - `gtrk tool image_classic_template a.jpg b.jpg c.jpg --main-title "新品速览"` — title + several images into a cover/collage; `--output-pic-count`/`--output-text-count` are clamped to 20 by the server.
613
+ - `gtrk tool image_vertical_stitch top.png mid.png bottom.png` — stitch several images vertically in the order given.
614
+ - `gtrk tool video_split_screen a.mp4 b.mp4 --output-ratio 16:9` — simple tier: automatic split-screen layout over the whole clips (reaction / side-by-side comparison).
615
+ - `gtrk tool video_split_screen a.mp4 b.mp4 --clips-json '[{"input":0,"begin_time_ms":0,"end_time_ms":5000},{"input":1,"crop":{"x":0.1,"y":0,"width":0.8,"height":1}}]'` — precise tier: specify each segment's millisecond range and normalized crop box by 0-based index; the same file can appear several times to fill several windows.
616
+ - `gtrk tool video_speaker_detect ./talk.mp4 --language zh-CN` — detect who is speaking and when on screen, emitting structured JSON (GPU heavy).
617
+ - `gtrk tool video_face_track ./talk.mp4 --params-json '{"time_ranges":[{"begin_time":0,"end_time":30000}]}'` face tracking / identity clustering, optionally limited to time ranges (**in milliseconds**; GPU heavy).
618
+ - `gtrk tool audio_tts_clone --text "欢迎收听本期节目" --speaker narrator` text to voice-over audio (the voice list is in the website docs).
619
+ - `gtrk tool audio_tts_clone --text-file 稿子.txt --speaker sweet_female --output-format mp3` long-form synthesis; by default it follows the speed and segmentation tuned for the chosen voice.
620
+ - `gtrk tool mad ./素材 [--bgm 歌.mp3] [--duration 20] [--seed 42] [--refresh] [--json]` — one-click MAD: scan the material folder → auto-select techniques → a single `.jsx` (run it once in AE 2020+ to get the master-composition project). `--seed` makes it reproducible; `result.json` records the seed, data version, degradation tier and chosen techniques.
621
+ - Common flags: `--out <dir>` overrides the output folder, `--param k=v` (repeatable) / `--params-json '<object>'` pass cloud parameters through, `--reupload` ignores the upload cache, `--json` is machine-readable, `--ffmpeg-path <dir>` points at an ffmpeg directory.
622
+ - Cloud-type tools without a key → an error pointing you at `gtrk init`. A failed artifact download (e.g. an expired link 404) → `result.json` records `errors` with `ok=false`, and `task.json` is kept so you can recover by `taskId`.
623
+ - Cleanup, upscaling and interpolation are long-running GPU jobs, and their descriptors poll for up to 4 hours. A wait timeout does not mean the job was cancelled; keep `task.json` / `result.json` and recover by `taskId` instead of re-running and paying twice.
624
+
625
+ The companion skill is `/gtrk-tools` (one skill covering the whole tool family).
626
+
627
+ ### Other
628
+
629
+ - `gtrk install [--api-key … -y --skill-agents codex,cursor --all-agents --copy-skills --skills-dir …]` — install everything in one command (skills + config + health check), modelled on Feishu's `lark-cli install`.
630
+ - `gtrk init [--api-key --api-base --jianying-draft-dir -y]` configuration only (interactive or not).
631
+ - `gtrk doctor` health check (including the CLI version and whether a newer one exists).
632
+ - `gtrk deps status` show **where** ffmpeg/ffprobe and the render fonts currently come from (`--ffmpeg-path` / `~/.gitruck` / system / missing), plus version, licence and source-code location.
633
+ - `gtrk deps install [--ffmpeg] [--font] [--force]` — install runtime assets from the Gitruck Cloud mirror, **skipping anything already present**.
634
+ - **It never downloads silently**: any missing-dependency path only errors out and points at this command (the packages are 30–90 MB and the distributed artifacts carry licence obligations, so a user or agent must trigger it explicitly).
635
+ - Downloads are always https with **strict sha256 verification**; anything that fails verification is discarded and never lands. Extraction uses the **system tar** (bundled with Windows 10+/macOS/Linux), pulling in no third-party decompression dependency.
636
+ - The resolution order is unchanged: `--ffmpeg-path` `~/.gitruck/ffmpeg` system `PATH`. The mirror only fills the middle slot and **never overrides an ffmpeg you installed yourself**.
637
+ - Fonts land in `~/.gitruck/fonts` and are supplied to burn-in through the ffmpeg `ass` filter's `fontsdir` — **never installed into the system font table, never written to the registry, never requiring administrator rights**.
638
+ - The distributed ffmpeg is a GPLv3 build, and the corresponding source is provided alongside the binaries (see `SOURCE.md` at the distribution point); **downloads carry no additional usage restrictions**.
639
+ - `gtrk upgrade [--check]` — upgrade the CLI to the latest version + refresh skills (config preserved); `--check` only reports.
640
+ - `gtrk skills install [--agents codex,workbuddy,comate,…] [--all] [--copy] [--dir <skills dir>]` — install/refresh agent skills on their own; by default the generic adapter and the gtrk supplement layer detect hosts automatically.
641
+
642
+ ---
643
+
644
+ ## How it works
645
+
646
+ ```
647
+ 本地 gtrk CLI 同合云 本地三端
648
+ ───────────── ───────────── ─────────────
649
+ 毛片 ──上传(指纹缓存免重传)──▶ video_oral_cut 智能剪辑 ──产物──▶ 客户端 gtrk/project.gtrk
650
+ (一次出 gtrk/剪映/xml) 剪映 自动落草稿目录
651
+ 源路径写进 gtrk materials.path PR/FCP 导入 premiere.xml
652
+ ```
653
+
654
+ - **gtrk** is a true superset of a timeline plus HTML particles, and it is Gitruck Cloud's unified project contract; all three formats derive from the same gtrk file, so their cut points agree.
655
+ - The cloud side needs **zero changes** and uses the existing `video_oral_cut`; the CLI only orchestrates (upload / submit / poll / fetch / place / open).
656
+
657
+ ## Notes
658
+
659
+ - Jianying / CapCut drafts require `draft_content.json` + `draft_meta_info.json` **as a pair** (and they must use exactly those **two filenames** — prefixed variants are not detected) before the app recognizes them. So either configure the draft folder with `gtrk init` or point at it with `--jianying-draft-dir`; otherwise only the content file is produced and you have to import it by hand. The CLI normalizes the filenames when copying into the draft root (`long2short` does the same per clip), while the output folder keeps the clip-prefixed archival names.
660
+ - When drive letters differ across machines, config lives under `~/.gitruck/` (user level; the old `~/.gtrk-cli` migrates automatically on first launch), and artifacts default to the raw file's folder.
661
+ - Pacing preset strength is decided by the cloud; `--preset` only picks a preset and does not change source trimming.
662
+
663
+ ---
664
+
665
+ ## Layout
666
+
667
+ ```
668
+ gtrk-cli/
669
+ ├── src/index.ts # commander 入口
670
+ ├── src/commands/ # subcommands: install / init / oralcut / long2short / transcript / split / matrix / mg / project / audio / tool / render / doctor / upgrade / skills / …
671
+ ├── src/lib/ # cloud / column-config / splitdoc / projection / user-config / jianying / …
672
+ ├── skills/ # 打包的框架 skills:oralcut / splitter / matrix / mg / ai-drama / style-maker / transcript / tools / music-visualizer / cover
673
+ ├── contracts/ # 框架契约库正本(gsap-emit v1 + handoff→契约映射表)
674
+ ├── assets/ # README 配图(介绍图 / Agent 调用示例 / 剪映草稿目录指引图)
675
+ └── AGENT.md # 可移植 agent playbook(skill 底座)
676
+ ```
677
+
678
+ A new command = write `register<Name>(program)` in `src/commands/<name>.ts` and register one line in `src/index.ts`.