返回 html-video
2026-05-26-spec-03-agent-skill.md
根目录 / research / 2026-05-26-spec-03-agent-skill.md
1 # RFC-03:Agent Skill 设计
2
3 > **Status**: Draft v0.1
4 > **Date**: 2026-05-26
5 > **Depends on**: [RFC-01](./2026-05-26-spec-01-engine-adapter.md), [RFC-02](./2026-05-26-spec-02-template-metadata.md)
6 > **Scope**: 本地 coding agent(Claude Code / Cursor / Codex / Gemini / OpenCode)通过 html-video 做视频的协议、CLI、决策逻辑
7
8 ---
9
10 ## 顶层架构
11
12 ```
13 ┌─────────────────────────────────────────────┐
14 │ coding agent (Claude Code / Cursor / ...) │
15 │ 读 SKILL.md → 调 html-video CLI │
16 └──────────────────┬──────────────────────────┘
17 │ stdio / shell
18 ┌──────────────────▼──────────────────────────┐
19 │ html-video CLI │
20 │ ┌────────────────────────────────────┐ │
21 │ │ Command router │ │
22 │ │ - search-templates │ │
23 │ │ - inspect-template │ │
24 │ │ - render │ │
25 │ │ - preview │ │
26 │ │ - list-engines │ │
27 │ └────────────┬────────────────────────┘ │
28 └────────────────┼──────────────────────────────┘
29 │ in-process call
30 ┌────────────────▼──────────────────────────────┐
31 │ @html-video/core │
32 │ - Template registry │
33 │ - Engine selector (capabilities-based) │
34 │ - Render orchestrator │
35 └────────────────┬──────────────────────────────┘
36 │ dynamic import
37 ┌────────────────▼──────────────────────────────┐
38 │ adapter-hyperframes / adapter-remotion / │
39 │ adapter-motion-canvas / adapter-revideo │
40 └────────────────────────────────────────────────┘
41 ```
42
43 **关键约束**:agent 只跟 CLI 打交道,**不**直接 import 任何 npm 包,**不**直接调 engine adapter。所有跨语言隔离 + 决策逻辑收敛在 CLI 层。
44
45 ---
46
47 ## CLI Contract(v0.1)
48
49 ### 全局 flags
50
51 ```
52 --json 输出 JSON(agent 默认带)
53 --no-color 关 ANSI(agent 默认带)
54 --cwd <path> 项目工作目录(默认 process.cwd())
55 --config <path> html-video.config.json 路径(覆盖自动发现)
56 --verbose 打印决策依据(debug)
57 ```
58
59 ### `html-video list-engines`
60
61 列出本机可用 adapters + 各自 capabilities。
62
63 ```bash
64 html-video list-engines --json
65 ```
66
67 输出(节选):
68
69 ```json
70 {
71 "engines": [
72 {
73 "id": "hyperframes",
74 "name": "Hyperframes",
75 "installed": true,
76 "version": "0.4.2",
77 "capabilities": { ... }
78 },
79 {
80 "id": "remotion",
81 "installed": false,
82 "install_hint": "pnpm add -D remotion @remotion/renderer"
83 }
84 ]
85 }
86 ```
87
88 ### `html-video search-templates`
89
90 按 intent / tags / category 检索。输出已经按 RFC-02 流程排好序。
91
92 ```bash
93 html-video search-templates \
94 --intent "show our github stars growth over the past 24 months" \
95 --aspect 16:9 \
96 --license-allow Apache-2.0,MIT,CC0-1.0,CC-BY-4.0 \
97 --top 5 \
98 --json
99 ```
100
101 输出:
102
103 ```json
104 {
105 "matches": [
106 {
107 "id": "data-bar-chart-race",
108 "name": "Bar Chart Race",
109 "engine": "motion-canvas",
110 "engine_installed": true,
111 "score": 0.91,
112 "score_reason": "tags=chart,race,data-driven match intent; aspect 16:9 supported; Apache-2.0 ok",
113 "preview_poster": "/path/to/preview.png",
114 "best_for": ["GitHub stars race", "Sales ranking", "..."]
115 },
116 { ... }
117 ],
118 "filtered_out": [
119 {
120 "id": "logo-reveal-cinematic",
121 "reason": "category=intro-outro doesn't match intent 'data growth'"
122 }
123 ]
124 }
125 ```
126
127 ### `html-video inspect-template`
128
129 返回某个 template 的完整 metadata,agent 借此了解需要哪些 inputs。
130
131 ```bash
132 html-video inspect-template data-bar-chart-race --json
133 ```
134
135 输出 = RFC-02 的 metadata + 一些 runtime info(resolved source path, cached preview URL...)
136
137 ### `html-video render`
138
139 实际渲染。
140
141 ```bash
142 html-video render \
143 --template data-bar-chart-race \
144 --vars-file vars.json \
145 --format mp4 \
146 --resolution 1920x1080 \
147 --fps 60 \
148 --duration auto \
149 --output /tmp/out.mp4 \
150 --json
151 ```
152
153 输出(streaming JSON 或 final summary):
154
155 ```json
156 {
157 "status": "ok",
158 "output_path": "/tmp/out.mp4",
159 "engine": "motion-canvas",
160 "duration_sec": 14.5,
161 "render_wall_clock_sec": 28.3,
162 "file_size_mb": 12.4,
163 "diagnostics": []
164 }
165 ```
166
167 如果 streaming 模式(`--stream-progress`),每秒 emit 一行 NDJSON:
168
169 ```ndjson
170 {"type":"progress","stage":"preparing","pct":5}
171 {"type":"progress","stage":"preparing","pct":10}
172 {"type":"progress","stage":"rendering","pct":12,"frame":108,"total_frames":870}
173 ...
174 {"type":"progress","stage":"muxing","pct":97}
175 {"type":"done","status":"ok","output_path":"/tmp/out.mp4",...}
176 ```
177
178 ### `html-video preview`
179
180 启 dev server 让用户在浏览器调(agent 调起后把 URL 推给用户)。
181
182 ```bash
183 html-video preview --template data-bar-chart-race --vars-file vars.json --json
184 ```
185
186 ```json
187 {
188 "url": "http://127.0.0.1:53219",
189 "engine": "motion-canvas",
190 "pid": 87234,
191 "stop_command": "html-video preview-stop --pid 87234"
192 }
193 ```
194
195 ### `html-video doctor`
196
197 诊断本机环境。Agent 在用户首次启动 html-video 时**应该先跑这个**,把缺的依赖补全提示给用户。
198
199 ```bash
200 html-video doctor --json
201 ```
202
203 输出:
204
205 ```json
206 {
207 "status": "warning",
208 "checks": [
209 { "name": "node-version", "status": "ok", "value": "v20.10.0" },
210 { "name": "ffmpeg", "status": "ok", "value": "ffmpeg version 7.0" },
211 { "name": "chromium", "status": "ok" },
212 { "name": "adapter-hyperframes", "status": "ok", "version": "0.4.2" },
213 { "name": "adapter-remotion", "status": "missing", "install_hint": "pnpm add -D @html-video/adapter-remotion" }
214 ]
215 }
216 ```
217
218 ---
219
220 ## SKILL.md(Claude Code 版)
221
222 放置位置:`@html-video/agent-skill-claude-code/SKILL.md`,用户 install 后 symlink 到 `~/.claude/skills/html-video/`。
223
224 ```markdown
225 ---
226 name: html-video
227 description: |
228 Generate HTML videos by orchestrating multiple rendering engines (Hyperframes,
229 Remotion, Motion Canvas, Revideo) through a unified CLI. Pick the right engine
230 per use case, fill template variables, render to MP4/WebM. Use when user asks
231 to "create video", "render video", "make a video", "数据动画", "演示视频",
232 "social short", or provides data/intent that fits a video format.
233 ---
234
235 # html-video skill
236
237 You orchestrate the `html-video` CLI to generate videos. Never call engine
238 adapters directly — always go through the CLI.
239
240 ## Initial check (run once per session)
241
242 ```bash
243 html-video doctor --json
244 ```
245
246 If `status` is `error` or critical adapters missing, surface install hints to
247 the user and stop. If `warning`, note the gap but proceed if user's intent
248 doesn't need the missing piece.
249
250 ## Standard workflow
251
252 ### 1. Understand intent
253
254 When user asks for a video, extract:
255 - **purpose** (data viz / social short / explainer / promo / ...)
256 - **input data** (if any — table, list, JSON, narrative)
257 - **aspect ratio** preference (16:9 / 9:16 / 1:1)
258 - **duration** target (if mentioned)
259 - **license needs** (commercial vs personal)
260
261 If any is unclear, ask **one batched question** before searching templates.
262
263 ### 2. Search templates
264
265 ```bash
266 html-video search-templates \
267 --intent "<extracted purpose+data summary>" \
268 --aspect <ratio> \
269 --license-allow <comma-list> \
270 --top 3 --json
271 ```
272
273 Show the user **top 3** results with poster image and score reason. Let them pick.
274
275 ### 3. Inspect chosen template
276
277 ```bash
278 html-video inspect-template <id> --json
279 ```
280
281 Read the `inputs.schema`. Compare with the data the user has provided.
282
283 - If user data already covers the schema → fill `vars.json`, skip to render
284 - If gaps → ask user **the missing fields only** (don't re-confirm what's
285 already known)
286 - If user data needs reshaping (e.g. user gave CSV, schema wants JSON
287 array-of-objects) → reshape silently, show before rendering
288
289 ### 4. Optional preview
290
291 If template's `performance.reference_render` suggests render will take
292 > 30 seconds, offer a preview first:
293
294 ```bash
295 html-video preview --template <id> --vars-file vars.json --json
296 ```
297
298 Open the URL in the user's browser. After their OK, render.
299
300 ### 5. Render
301
302 ```bash
303 html-video render --template <id> --vars-file vars.json \
304 --format mp4 --resolution 1920x1080 --fps 60 \
305 --output ~/Desktop/<descriptive-name>.mp4 \
306 --stream-progress --json
307 ```
308
309 Surface progress to user every 25% (preparing / rendering 25% / 50% / 75% /
310 muxing / done). On done, paste the absolute output path.
311
312 ### 6. On errors
313
314 - `engine-not-installed` → run `html-video doctor` and surface install hints
315 - `template-invalid` → re-inspect template, check vars match schema
316 - `render-failed` → read `diagnostics` array, propose fix, ask user before retry
317 - `render-timeout` → ask user if lower resolution / shorter duration is OK
318
319 ## Anti-patterns (don't do these)
320
321 - ❌ Don't pick a template silently — always show top 3 with reasons
322 - ❌ Don't render a 60-second video without offering preview first
323 - ❌ Don't re-ask for vars the user already provided
324 - ❌ Don't fall back to a different engine on render failure without telling
325 the user (the user might have license / aesthetic reasons for the choice)
326 - ❌ Don't write to engine-native files directly — only edit `vars.json`
327
328 ## Quick reference
329
330 | Task | Command |
331 |---|---|
332 | Health check | `html-video doctor --json` |
333 | Find templates | `html-video search-templates --intent "..." --json` |
334 | Read template | `html-video inspect-template <id> --json` |
335 | Render | `html-video render --template <id> --vars-file vars.json --output <path> --json` |
336 | Preview | `html-video preview --template <id> --vars-file vars.json --json` |
337 | List engines | `html-video list-engines --json` |
338 ```
339
340 ---
341
342 ## Cursor / Codex / Gemini variants
343
344 不重写一遍。用 [`@html-video/agent-skill-claude-code`](#) 作为 master,**自动 transpile** 成:
345
346 - `@html-video/agent-skill-cursor` —— `.cursor/rules/html-video.mdc` 形式
347 - `@html-video/agent-skill-codex` —— `~/.codex/skills/html-video.md`
348 - `@html-video/agent-skill-gemini` —— `~/.gemini/agents/html-video.toml`
349 - `@html-video/agent-skill-opencode` —— OD 项目内 `.opencode/skills/html-video/`
350
351 transpile 工具藏在 `tools/skill-transpile/`,CI 跑。所有变体共享 SKILL.md 的 prose,只换 frontmatter / file 命名。
352
353 ---
354
355 ## Engine 选择逻辑(agent 不必懂细节,但放这里供 review)
356
357 CLI 内部决策伪码:
358
359 ```ts
360 function selectEngineForTemplate(template, userPrefs, installedEngines) {
361 // Stage 0: template 已经声明 engine,必须用这个 engine 的 adapter
362 const targetEngine = template.engine;
363 const adapter = installedEngines.find(e => e.id === targetEngine);
364
365 if (!adapter) {
366 return {
367 ok: false,
368 reason: `Template requires ${targetEngine} but it's not installed`,
369 install_hint: `pnpm add -D @html-video/adapter-${targetEngine}`
370 };
371 }
372
373 // Stage 1: validate template against adapter capabilities
374 const validation = adapter.validate(template);
375 if (!validation.ok) {
376 return { ok: false, reason: validation.errors[0].message };
377 }
378
379 // Stage 2: license filter
380 if (userPrefs.commercial && template.license.commercial_use === false) {
381 return { ok: false, reason: 'Template not licensed for commercial use' };
382 }
383
384 // Stage 3: aspect / format / fps 兼容
385 if (userPrefs.format && !adapter.capabilities.outputFormats.includes(userPrefs.format)) {
386 return { ok: false, reason: `Engine ${targetEngine} doesn't support ${userPrefs.format}` };
387 }
388
389 return { ok: true, adapter };
390 }
391 ```
392
393 注意:**v0.1 不做 cross-engine fallback**(一个 template 只对应一个 engine)。如果 agent 想"换 engine 试试",让它重新 search-templates 选另一个 template id。
394
395 ---
396
397 ## 监控 / 遥测(可选)
398
399 `html-video.config.json` 可加:
400
401 ```json
402 {
403 "telemetry": {
404 "enabled": false,
405 "endpoint": "https://html-video.nexu.io/telemetry"
406 }
407 }
408 ```
409
410 默认 **off**。开了后只发匿名渲染统计(template id, engine, duration, success/fail),**不**发用户 vars 内容。Apache-2.0 + 显式 opt-in 是底线。
411
412 ---
413
414 ## 用户交互范例(实际对话)
415
416 ```
417 User: 帮我做个视频,展示 OD 仓库 GitHub stars 25 天涨 5 万的曲线
418
419 Agent (内部跑 search):
420 → html-video search-templates --intent "github stars growth over time" --aspect 16:9 --top 3 --json
421
422 Agent (回应用户):
423 我找到 3 个匹配的模板,你想用哪个?
424
425 1. **Bar Chart Race** ★★★ (Motion Canvas)
426 [poster.png]
427 适合:rankings 对比 / 多 entity 演变
428 时长:5-60s 可调
429 License: Apache-2.0
430
431 2. **Line Chart Animation** ★★ (Hyperframes)
432 [poster.png]
433 适合:单指标随时间演变(你这个场景)
434 时长:3-30s
435 License: Apache-2.0
436
437 3. **Number Counter Reveal** ★ (Hyperframes)
438 [poster.png]
439 适合:单数字爆炸式 reveal
440 时长:3-10s
441
442 User: 第二个
443
444 Agent: 我看了 Line Chart 模板需要这些数据:
445 - data: 时间序列 (date + value)
446 - title: 标题(≤80字)
447 - y_axis_label: Y 轴标签
448
449 你的 25 天数据我能帮你拉,但 GitHub API 翻页限制可能不全,要不要我用 growth-dashboard 已 backfill 的数据?
450
451 User: 用 dashboard 的
452
453 Agent (调 growth-dashboard 的 SQLite 拉数据 → 整成 JSON → 渲染):
454 好。Title 我用 "Open Design GitHub Stars · 25 Days to 50K",
455 y 轴 "Stars (cumulative)"。开始渲染...
456
457 [progress 25% / 50% / 75%]
458
459 ✅ 渲染完成
460 /Users/joey/Desktop/od-stars-50k-race.mp4 (1920×1080, 14.5s, 12 MB)
461 ```
462
463 ---
464
465 ## Open Questions(v0.2 待定)
466
467 1. **Skill 之间的协作**:html-video skill 想调 growth-dashboard 的数据 → 是直接读 SQLite 还是走 cross-skill MCP?v0.1 让 agent 自己 bridge
468 2. **Multi-shot 工作流**:用户说"做个视频,60 秒,前 10 秒 logo reveal、中间 40 秒 chart race、最后 10 秒 CTA" → 需要 timeline composer skill。v0.2+ 才考虑
469 3. **缓存层**:相同 template + 相同 vars 多次 render 是否复用?倾向加 content-hash cache,但 v0.1 先不做
470 4. **OpenCode 集成**:OD 用 opencode 跑 agent;html-video 是否也注入 opencode skill registry?等 OD client 那边的 skill 接入接口稳定再做
471
471 lines MARKDOWN