DeepSeek Harness 实战为浏览器交互录制可信演示 GIF 并发布到 Pull Requestrecord-browser-gif 技能全解【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness本指南围绕仓库内置的record-browser-gif技能展开讲解如何在 DeepSeek Harness 中为产品用户可见的 GUI 变更录制一段真实、可追溯、可发布的浏览器演示 GIF从按 PR 提交搭建真实服务器、用浏览器控制工作流必要时回退 Playwright 兜底录制视频或截图到用确定性编码器产出体积可控的 GIF再到通过gh --attach或独立 assets 分支把产物发布进 PR 正文。读完你可以完整复现这条单次真实运行 → 本地产物 → 发布校验的证据链并理解每一条规则背后的源码依据。技能定位什么场景触发 record-browser-gif技能定义见 SKILL.md明确了两类触发条件用户明确要求制作 / 录制 / 生成一个演示浏览器工作流的 GIF每一个改变产品用户可见 GUI 行为的 Pull Request都必须包含一段按本技能录制、并通过发布流程嵌入 PR 正文的演示 GIF。技能的核心原则不是录一段好看的动画而是让 GIF 成为证据它必须来自该 PR 分支树启动的真实服务器、真实 API key 和真实模型轮次而不是 fixture 查询、mock 传输、合成事件注入或测试专用钩子——除非用户明确要求录制 fixture 版本。在嵌入 GIF 的同时还需要在 PR 里声明精确的演示提交 SHA、服务该提交的 tree 与 origin、任何模式开关或浏览器状态例外、以及是否真的跑了一轮真实模型。这一设计决策的完整论证记录在仓库笔记 2026-08-08-browser-gif-evidence-chain.md 中一组各自看起来真实的截图并不能证明一次真实的执行而本技能强制一个 storyboard 对应一次隔离运行、发布时重新校验产物与演示 PR 的 head从而把证据链闭合。录制与发布两阶段严格分离技能把整条流水线切成两个互不越界的阶段录制只产生本地视频或截图以及一个.gif产物永不修改远端状态发布是把 GIF 附加到 PR 正文gh --attach或推送到独立 assets 分支再嵌入其 URL永不触碰 PR 自己的分支并且只在任务包含把 GIF 附加到 PR时才执行。两个硬性约束值得记住真实服务器 / 真实 API 的演示不得用 fixture 或 mock 代替若凭据或服务器不可用应当报告这个限制而不是悄悄换用 fixture同时绝不读取或暴露凭据值API key 通过应用正常配置路径注入配合一个良性的演示提示词。第一阶段按 PR 搭建应用StageGIF 必须演示该 PR 的那棵树因此要按 PR 逐次搭建要求干净的工作树用git rev-parse HEAD记录精确提交然后构建这棵树pnpm run build pnpm run build:web。对另一个提交的构建录 GIF会错误归属证据。从这棵树为每个端口启动一个服务器使用全新的 scratch 状态DSH_HOME、DSH_AGENTS_HOME、工作区、会话状态。浏览器同样使用全新的隔离 context/profile若浏览器工作流无法创建新 context则必须在导航前清除该 origin 的 cookie 与站点存储防止既有客户端状态污染证据。API key 通过应用的正常路径从仓库根.env注入绝不回显。一个 storyboard 就是一次证据运行所有发布的帧必须来自同一个服务器、同一组状态根、同一工作区、同一会话、同一模型支撑场景。若采集自动化失败丢弃其帧并从全新根状态重跑严禁把多次运行的帧拼接。在多个 PR 之间切换时用PID 或命令行的精确匹配停止旧服务器——宽泛的pkill -f模式可能误杀启动它的 shell包括你自己所在的 shell。第二阶段录制流程Record the flow优先使用仓库提供的浏览器控制工作流按其 setup / interaction / cleanup 说明执行当它暴露recordVideo时在同一受控 context 上开启视频以获得更多中间帧否则使用其截图采集能力。视频可用性不决定选用哪个浏览器控制工作流。既有用户浏览器状态是显式的隔离例外仅在用户要求或必须时使用并在 GIF 旁注明。只有浏览器控制不可用时才回退到仓库声明的 Playwright 依赖在隔离的无头浏览器中录制并在采集说明中注明这一回退。在本仓库中该依赖解析自 apps/web/package.jsondevDependencies 中声明playwright: ^1.49.0不要另装驱动也不要打开用户自己的浏览器。录制前还要确认origin、构建或开发服务器、传输方式、任何模式覆盖。当生产默认会打开自动化无法驱动的原生界面时应通过正常应用配置选择一个官方的、可被浏览器操作的生产后端并如实披露该覆盖。所有中间产物统一存放到仓库 gitignored 的.playwright-mcp/目录下仓库根 .gitignore 第 43 行已确认该目录被忽略包括录制脚本、原始视频、时间注释、QA 帧和最终 GIF。先创建运行目录。采集视频捕获高帧率中间态视频模式下有一个极易踩的坑viewport与recordVideo.size必须显式匹配否则 Playwright 会把视频缩放到 800×800 以内导致 UI 文字不可读。独立 Playwright 回退的参考脚本const { chromium } createRequire(join(repo, apps/web/package.json))(playwright) const browser await chromium.launch() const size { width: 1440, height: 900 } const context await browser.newContext({ viewport: size, recordVideo: { dir: join(runDir, videos), size }, }) try { const page await context.newPage() const video page.video() // 在这里导航并操作真实应用。 await context.close() await video.saveAs(join(runDir, demo.webm)) } finally { await context.close() await browser.close() }其中createRequire从node:module导入、join从node:path导入repo与全新的runDir在录制脚本中设为绝对路径。几个关键细节在关闭页面/context 前保留 video 句柄先await context.close()再video.saveAs()因为只关浏览器不保证视频刷盘完成每个 page 各有自己的视频必须显式选择要演示的那个页面不要拼接无关页面或无关运行失败运行只作诊断用途。讲一个 36 个状态的小故事选择一段包含 3 到 6 个有意义状态的短故事。操作前等待唯一的语义定位符可访问名称相等与精确文本完成判定要使用exact: true避免把提示词回显或后代文本误当结果。固定等待只能用于状态验证后的阅读保持永远不能用来确立就绪。采集视频时保留动画与滚动。演示工具调用、拒绝或恢复时打开其 detail 或 trajectory让视频呈现工具身份、状态或稳定错误码、以及下游结果。若某个瞬态运行状态很重要就提示一个慢速前台操作并观察其具体 DOM 标记连续视频会捕捉中间帧。给模型一个简短的最终 sentinel 来锚定完成演示状态可见后即可停止过长的真实 API 运行。安全底线不采集秘密、个人数据、无关标签页或通知。浏览器视频只含页面内容而非浏览器 chrome因此也要避免在应用内渲染带凭据的 URL。审阅整个选定区间含中间状态全程保持单一 viewport。第三阶段确定性编码 GIFencode_gif.py编码阶段依赖python3、ffmpeg、ffprobe。若媒体二进制缺失报告该依赖而不是未经授权安装软件。GIF_SKILL_DIR必须在单独一行export因为内联赋值在同一命令中无法影响参数展开export GIF_SKILL_DIR/absolute/path/to/this/skill python3 $GIF_SKILL_DIR/scripts/encode_gif.py \ /absolute/path/to/demo.webm \ /absolute/path/to/demo.gif \ --start 2 --end 32 --speed 2 --final-hold 3 \ --fps 10 --max-width 1200 --colors 128脚本位于 scripts/encode_gif.py其命令行契约定义在build_parser()见 encode_gif.py。参数语义如下参数默认值说明input—WebM 视频文件或有序截图目录output—输出.gif路径后缀必须为.gif--start/--end0 / 视频末尾截取一个连续源区间秒。需满足0 ≤ start end ≤ 源时长否则拒绝encode_gif.py--speed1播放倍速。调速后必须与所选区间一起披露避免让演示暗示真实响应延迟--final-hold2最终帧额外保持秒数用tpadstop_modeclone重复最后一帧实现--fps10编码帧率上限 30提高 fps 无法恢复源录制未捕获的运动--max-width1200输出最大宽度scalemin(max_width,iw):-2:flagslanczos--colors128调色板颜色数必须介于 4256--max-bytes5 MBDEFAULT_MAX_BYTES见 encode_gif.py输出字节上限超出即失败--force关覆盖已存在的输出文件仅在确认目标路径后使用--pattern/--durations*.png/ 每帧 2 秒仅用于截图目录输入默认行为是保留完整视频、1× 速度、追加 2 秒末尾保持。使用观察到的视频时间而非猜测的墙钟偏移并保留演示行为的完整因果。原始 WebM 必须留存做 QA不要拼接不同运行或合成缺失状态。从源码看编码器做了完整的防御校验见 encode_gif.py视频输入探测WebM 容器时长Playwright 的 WebM 不写流时长因此读formatduration拒绝空区间、越界区间、短于两个输出帧的选择、模式不符的标志、意外覆盖拒绝输入为截图目录却传入--start/--end/--speed/--final-hold反之亦然以及输出路径与输入相同截图目录要求至少两帧、所有帧尺寸一致、duration 数量与帧数一致滤镜链为trim/setpts → fps → scale → tpad(视频) → split → palettegen(max_colors) → paletteuse(ditherbayer)见 encode_gif.py编码后回读产物校验时长容差max(0.2, 2/fps)秒、宽度、动画帧数 ≥ 2、字节数全部通过后才输出 JSON 摘要字段含sourceVideo/startSeconds/endSeconds/speed/finalHoldSeconds/sourceFrames/encodedFrames/width/height/durationSeconds/fps/bytes。配套测试 scripts/test_encode_gif.py 通过真实 ffmpeg/ffprobe 子进程验证了 trim/倍速/末尾保持/调色板顺序、默认保留全长、非法参数不写输出、截图 duration 与视频标志互斥、覆盖保护与--max-bytes上限等行为是理解编码器语义的最佳参考。截图模式无连续视频时的 storyboard当连续视频不可用或用户要求 storyboard 时用浏览器控制工作流的截图 API 在一次隔离运行中采集 36 个已验证状态直接把返回的图片字节存入同一运行目录命名为00-initial.png、01-typed.png等保持相同尺寸与裁剪。瞬态状态要轮询其 DOM 标记并在同一浏览器脚本调用内采集python3 $GIF_SKILL_DIR/scripts/encode_gif.py \ /absolute/path/to/frames /absolute/path/to/demo.gif \ --durations 1.5,1.5,1.5,3.5 --fps 10 --max-width 1200 --colors 128--durations传一个值则应用于每张截图否则为每帧提供一个正时长让稳定状态保持最久。目录输入拒绝少于两帧、尺寸不一致或时长数不匹配的输入。第四阶段验证产物Verify编码完成不等于可以发布按四步验收读取编码器的 JSON 摘要确认输出路径、源区间与速度或截图数、编码帧数、尺寸、时长与字节数直接视觉阅读编码后的 GIF 本身而非源帧确认过渡清晰、末态保持足够长、无敏感内容。若查看器只渲染首帧用ffmpeg从编码后的 GIF解码代表性帧再检查——编码前的截图不能证明编码后的顺序、调色板或末尾保持git status --short确认原始视频、QA 帧和产物只落在被忽略的路径下返回 GIF 绝对路径客户端支持时渲染它并声明录制用的是真实 API、fixture 还是其他传输。若任务不包含附加 GIF 到 PR到这里就结束。编码器维护安装媒体前置依赖后运行python3 -m unittest discover -s $GIF_SKILL_DIR/scripts -p test_*.py -v。这些本地媒体测试不参与仓库 CI需在本地维护。第五阶段发布Publish仅当任务包含把 GIF 附加到 PR时执行本阶段。永远不要把 GIF 提交到 PR 自己的分支或任何会并入长寿命分支的分支——二进制媒体提交会永久膨胀每个未来克隆的仓库历史。首选gh --attach一次命令完成上传并原地改写正文引用任何分支都不携带媒体。首选gh --attach前提条件gh≥ v2.99.0gh --version确认、仓库位于 github.comGitHub Enterprise Server 不支持、有仓库写权限、GIF ≤ 10 MB。先确认已验证产物满足该上限超出则先用--max-width、再--colors或--fps缩小。在正文文件中把 GIF 写成普通本地路径引用路径与传给--attach的一致gh会原地把引用改写为上传后的 URL保留其位置与 alt 文本alt text演示的 PR 通常是发布目标工具类 PR 可以嵌入来自另一个 PR 的、清晰标注的示例但必须指名源 PR 并在每项检查中对比其 live head绝不把示例归属到工具分支。附加前立即重读演示 PR 的 live head对新 PR 即推送的分支 tip与 GIF 旁记录的提交比对若已移动则停下重录。然后执行gh pr create --body-file body.md --attach path/to/demo.gif # 新建 PR gh pr edit pr --body-file body.md --attach path/to/demo.gif # 已有 PR--attach可重复使用但拒绝同一文件两次。正文未引用到的 GIF 会被追加到末尾此时可用标志上的 alt 文本--attach path#alt text被改写的引用则保留正文的 alt 文本。附加后重读演示 live head 确认仍停留在记录提交重读 live body 确认引用已指向上传 URL用 GitHub 的 Markdown API 渲染正文并确认出现预期img抓取上传 URL 一次确认200且内容类型为image/gif。回退独立 assets 分支仅当gh --attach无法使用时采用GIF 仍超 10 MB、gh版本低于 v2.99.0、或仓库不在 github.com。此时 GIF 存放在一个专用的孤儿 assets 分支上——没有父提交、只含媒体的分支一个 assets 分支服务整个 PR 系列命名为series-assets用git ls-remote --heads origin *assets*列出已有分支。任一流程推送前都要验证assets 分支只含媒体且暂存的 GIF 校验和与已验证的本地产物一致。已有 assets 分支时在浅单分支的 scratch 克隆中操作保证发布流程碰不到你的工作树git clone --branch assets-branch --single-branch --depth 1 repo-url /tmp/assets-checkout cp /absolute/path/to/demo.gif /tmp/assets-checkout/name.gif cd /tmp/assets-checkout git add name.gif git commit -m assets: what it shows gif (#pr) git push origin assets-branch新系列则先git clone --depth 1 repo-url /tmp/assets-checkout再用git switch --orphan assets-branch创建孤儿分支之后同样添加、提交、推送。推送后使用认证的 GitHub API 或 raw 请求确认远端路径、字节数、校验和、200响应与image/gif内容类型——匿名404不能否定私有仓库资产需要认证验证。这证明的是仓库成员评审路径而非公开可用性。编辑 PR 正文前重读演示 PR 的 live head 并与记录提交比对编辑后再次重读并要求仍停留于该提交再用 GitHub Markdown API 渲染正文确认预期img存在。正文中嵌入raw blob URL必须带?rawtrue纯 blob URL 渲染的是 GitHub 文件页而非图片assets 分支绝不删除、绝不改写、绝不 force-push已合并 PR 的正文将永久引用其 URL只允许追加新提交。小结一条可审计的证据链回顾整套流程record-browser-gif的核心并非录 GIF而是把一次演示压缩成单次真实运行的因果证据按提交构建的真实树、全新状态根、精确语义等待、确定性编码、产物级校验、发布前对 PR live head 的双重复核以及上传后对可达性与媒体类型的再验证。从 证据链笔记 的问题定义到 编码器 的每个校验分支仓库把真实、可复核落成了可执行的规则——这也是它成为 DeepSeek Harness 中 GUI 变更 PR 事实标准的原因。【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考