儲存庫教學影片
目標是製作一部讓團隊成員能觀看並理解儲存庫的影片:它做什麼用的、各部分如何組合在一起、每個功能實際執行結果,包括目前哪些功能壞了。這項技能混合了兩種任務,應依序執行:
- 實際測試儲存庫。 影片中顯示的每個指令都真的跑過,且確實讀取了它的輸出。
- 以故事形式錄製。 章節按照系統的結構組織,每一章節都有旁白。
只顯示成功指令的影片會誤導團隊。你在測試中發現的失敗往往是影片最有價值的部分,所以給它們一個獨立的結尾章節。
輸出目錄結構
在儲存庫外部的目錄中工作。由使用者指定;如果他們沒有指定,則使用相鄰目錄,例如 <parent-of-repo>/video/,因為以磁碟根目錄開頭的路徑(如 /video)在 macOS 上通常是唯讀的。
video/
├── <name>-walkthrough.mp4 # 完整影片:章節 + mov_text 字幕軌
├── <name>-walkthrough.srt # 相同的旁白,也可作為逐字稿使用
├── chapters/NN-slug.mp4 # 每個章節一個檔案
├── README.md # 章節索引(含開始時間)與如何重新錄製
├── src/ # engine.py, make_readme.py, script.py (+ 輔助檔案)
├── work/ # 可丟棄的儲存庫複本:所有指令在這裡執行
└── build/ # 中間檔案(各段落語音、幀、片段)
絕對不要在使用者的工作目錄中執行示範指令。把它複製到 work/ 目錄(git clone <repo> work/<name>),這樣影片就可以刻意破壞東西(錯誤的 manifest、注入的錯誤)並透過 git checkout . && git clean -fd 重置。如果使用者的工作目錄有未提交的變更,請提及它們並保持不變。
步驟 1:檢查工具,並告知使用者缺少什麼
which vhs ffmpeg ffprobe jq; python3 -c "import PIL; print(PIL.__version__)"; say -v '?' | head -3
如果任何東西缺失,告訴使用者需要安裝什麼以及原因,然後再安裝(brew install vhs ffmpeg jq)。對於 Pillow,不要動系統的 Python。改用 uv 執行引擎:uv run --no-project --with pillow python engine.py ...。將其包裝成一個 shell 函數(py() { uv run --no-project --with pillow python "$@"; }),因為用變數存放指令不會正確展開。儲存庫所需的任何其他東西也是如此,例如 Docker 正在執行、模擬器堆疊或憑證。向使用者詢問這些,永遠不要捏造機密。高品質語音(系統設定 → 輔助使用 → 口語內容,例如「Ava (Premium)」)聽起來比預設的 Samantha 好得多。建議使用,但不要因此卡住;VOICE=... engine.py --force 稍後可以重新調整語音。
步驟 2:在寫任何旁白之前,先理解並測試儲存庫
閱讀 README、文件或 ADR、CLI 入口點(每個子指令的 --help)、測試標記、Makefile 和 CI 配置。建立一份每個功能的清單,使用者可以操作:每個 CLI 子指令、每個測試套件、每個整合、每個程式碼要防禦的失敗模式。
然後在 work/ 中全部執行,並記錄:
- 能清楚展示每個功能的確切指令,並搭配簡短輸出(透過
jq、head、tail、cut -c1-160處理) - 哪些東西失敗了,以及這是真正的錯誤還是只是你的環境問題(錯誤的預設路徑、缺少環境變數)。在複本中或用環境變數修正環境問題,並讓這個修正在影片中可見,因為團隊也會遇到同樣的問題。
- 如何刻意破壞每個安全規則(一個 fixture,在複本上用
sed),這樣影片可以展示規則被觸發的樣子
這些筆記將成為發現章節的內容。把它們整理成一個編號的具體項目清單。
步驟 3:規劃章節
遵循系統本身的流程,而不是目錄列表。一個效果很好的結構:
| # | 章節 | 內容 |
|---|---|---|
| 00 | 歡迎 | 標題卡片,然後是「你將會看到」的投影片 |
| 01 | 總覽 | 一句話的目的、以方框和箭頭表示的流程、儲存庫布局的終端機畫面 |
| 02 | 設置 | 安裝、按用途分組的 CLI、快速測試套件 |
| … | 每個流程階段一章 | 真實指令,加上每個規則的「刻意破壞」場景 |
| … | 即時 / 整合 | 實際的後端服務,端到端 |
| N-1 | 合約 / 交接 | 其他團隊依賴的內容 |
| N | 發現與下一步 | 編號的發現清單,然後是下一步該做什麼 |
目標是每章 1–3 分鐘,總長 15–25 分鐘。一個章節是一個想法;一個段落是一個畫面加上一段旁白。在錄製之前向使用者展示這個大綱(章節標題和每個一行說明)。
步驟 4:撰寫 src/script.py
將隨技能提供的腳本複製到影片目錄中:
mkdir -p video/src && cp <skill-dir>/scripts/{engine.py,make_readme.py,agent.jq} video/src/
cp <skill-dir>/scripts/script_template.py video/src/script.py
script.py 包含所有文字和所有指令。engine.py 將其轉換為影片。請閱讀 references/script-format.md 取得完整的段落結構、投影片佈局和旁白風格。scripts/script_template.py 展示了每種段落類型及其運作範例;按照相同的結構(步驟 3 給出了章節大綱)建立其餘章節。
最重要的旁白規則:
- 為聽覺而寫:短句、無 markdown,並拼出語音會發錯音的縮寫(
「M C P」、「C L I」),或者將它們加入script.py的SPOKEN中。 - 告訴觀眾要看什麼(「看一下技能:零」)。語音和畫面必須一致,所以如果你改變了指令的輸出(計數、速度因數),也要修正句子。
- 字幕(終端機畫面的底欄)是一行陳述要點的文字,其中關鍵字以
code反引號標記。
步驟 5:乾執行,然後錄製
cd video/src # `py` = 附帶 Pillow 的 Python(參見步驟 1)
py engine.py --dry # 在純 bash 中執行每個終端機指令並印出輸出,不產生影片
py engine.py --dry --only 04 # 一個章節
py engine.py --only 04 # 錄製一個章節(快速回饋外觀)
py engine.py # 所有缺失或已變更的內容,然後組裝完整影片
py engine.py --only 07 --reuse-terms # 保留 VHS 片段,只重做語音和畫面(旁白修正)
py make_readme.py # 寫入含章節索引的 README.md
一定要先乾執行。只需幾分鐘而不是一小時,並且能捕捉到每個會出錯、卡住或輸出太多的指令。先錄製一個章節並在完整建置前檢查畫面:
ffmpeg -v error -ss 20 -i chapters/04-*.mp4 -frames:v 1 build/check.png # 然後檢查該 PNG
完整建置需要很長時間(約 21 分鐘的影片需要 40 分鐘)。在背景執行它,並等待其完成通知,而不是輪詢。章節會根據其腳本的雜湊值快取,因此重新執行只會重建有變更的部分。
步驟 6:驗證並交付
ffprobe -v error -show_chapters -show_streams -of compact video/<name>-walkthrough.mp4 | head -40
檢查以下項目:
- 影片長度
- 1920×1080 h264、aac 和 mov_text 字幕串流
- 每個章節一個章節標記
- 從幾個章節中抽樣畫面:文字沒有溢出方塊,字幕在兩行內
然後告訴使用者 MP4、chapters/ 目錄、SRT 和 README 的完整路徑。加上如何開啟(open video/<name>-walkthrough.mp4;QuickTime 或 VLC 會顯示章節和字幕選單)以及發現清單。提及任何你留下仍在執行的容器或服務,以及如何停止它們。
已解決的陷阱(編輯引擎時請記住這些)
- 沙箱 shell: vhs、Docker、
uv快取和say經常在指令沙箱(「不允許操作」、Docker socket 錯誤)下失敗。這些指令需要在沙箱之外執行。open也會被封鎖,所以給使用者一個他們自己可以執行的指令。 - VHS 掉幀: 預設的 50 fps 在長時間的場景中會掉幀。引擎使用
Set Framerate 15。 - VHS
Output必須是純檔案名稱。 將cwd設定為輸出目錄來執行vhs。 - VHS 字串沒有跳脫。
json.dumps的引號會破壞 PS1 跳脫序列。使用引擎中的q(),它會選擇一個文字中不包含的"、'或`分隔符。 Wait會卡住,如果模式不符合提示字元。引擎設定一個以$結尾的 PS1,並使用WaitPattern /[>$]$/。如果指令印出的最後一行以$或>結尾,可能會提早結束等待,所以在那裡加上pause。- 長時間執行的場景(AI 代理、管線執行):在段落上設定
"speedup": True。引擎會將片段加速到大約旁白的長度,並在標頭印上sped up ×N.N,所以要在旁白中說這是加速的。 - 投影片文字溢出:
wrap()會以等寬字型測量程式碼片段。保持方塊主體簡短,並將長路徑分成兩行。 - 等待迴圈:
pgrep -f <pattern>迴圈會比對到自身。改為等待一個 PID 或檔案。 - 前置掛鉤(章節上的
"before": [...])用於準備狀態:重置 DB 容器、觸發管線、注入錯誤。將復原(重置、取消注入)放在同一個章節中,這樣重建一個章節就不會讓平台處於損壞狀態。 - 示範需要的機密放在複本中一個被 git 忽略的檔案裡(例如
dev-vault.env)。絕對不要在畫面上顯示它們的值,也永遠不要提交它們。
展示 AI 代理工作(選擇性)
如果儲存庫建置或配置了一個代理,最有力的場景是代理診斷一個真實注入的錯誤。以無頭模式執行並輸出 stream-json,然後用隨附的 agent.jq 格式化串流(每行一個工具呼叫,然後是答案):
claude -p "<question>" --output-format stream-json --verbose | jq -rj -f /path/to/video/src/agent.jq
將該段落標記為 "speedup": True,並在同一個章節中稍後重置該錯誤。