Background
Web screen recording landed in v0.18.0 (#885, #891). The commands are:
agent-device record start <path> --platform web
agent-device record stop
Output is a .webm file (extension-enforced: non-.webm paths are rejected). Unlike Android (where adb screenrecord encodes on-device), the web path has no device to encode on: the managed agent-browser backend polls CDP Page.captureScreenshot at a fixed frame rate and pipes those frames to a system/PATH ffmpeg that encodes the webm host-side (VP8/libvpx). The shell-out is a bare Command::new("ffmpeg") in agent-browser's cli/src/native/recording.rs — no bundled binary and no path/env override — so ffmpeg is a hard runtime dependency of web recording.
Problem
agent-device web setup installs the managed agent-browser/Chromium backend, but it does NOT install ffmpeg. On a runner without a system ffmpeg, recording fails — and the failure surfaces on record stop, not record start, because record start launches the encoder detached and returns success; the spawn error (ENOENT) is only collected when record stop joins it:
Error (COMMAND_FAILED): ffmpeg not found or failed to execute: No such file or directory (os error 2). Install ffmpeg to enable recording.
Hint: Run `agent-device web setup` to install the managed web backend.
Two issues:
- The hint is misleading. Running
web setup does not resolve the error, because setup does not install ffmpeg.
- Every CI consumer must hand-install ffmpeg. ffmpeg is not pre-installed on GitHub-hosted Ubuntu 24.04 runners (not listed in the
actions/runner-images Ubuntu2404 "Installed Software" manifest), so a headless CI recording use case has to add a separate step (e.g. apt-get install ffmpeg) — friction the tool could remove, the same way it already provisions the browser.
Proposed solution
Provision the encoder alongside the managed backend, the way Playwright ships its own ffmpeg during playwright install. The whole fix can live in agent-device — no agent-browser code change is required.
- Make a managed ffmpeg discoverable via
PATH (primary fix, self-contained). On --platform web, agent-device already spawns the pinned agent-browser CLI with a controlled environment — managedAgentBrowserEnv() in src/platforms/web/agent-browser-tool.ts returns { ...process.env, HOME, AGENT_BROWSER_SOCKET_DIR }, and record start runs through that env. Prepend a managed-ffmpeg bin dir to PATH there. Because agent-browser invokes a bare Command::new("ffmpeg") that inherits its process PATH, the ffmpeg grandchild then resolves the managed binary — with no change in agent-browser.
- Install the managed ffmpeg during
web setup. Hook into setupManagedAgentBrowser() (the same flow that installs the browser) to fetch a pinned, per-platform static ffmpeg (built with libvpx/VP8) into the managed backend dir.
- Add an ffmpeg check to
web doctor. Extend doctorManagedAgentBrowser() to probe managed-then-system ffmpeg and verify it can actually encode VP8/webm (not just print -version), reporting presence/version/capability clearly.
- Keep a Playwright-style skip-download opt-out (cf.
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD) that skips the managed ffmpeg and falls back to a system/PATH ffmpeg.
Optional hardening (not required): an ffmpeg-path env override in agent-browser would make discovery explicit (immune to PATH order / a stray earlier system ffmpeg). It is redundant for correctness once PATH injection is in place, so it should be a follow-up rather than on the critical path.
Acceptance criteria
- On a runner that provably has no system ffmpeg (test asserts
! command -v ffmpeg first), after agent-device web setup, an agent-device record start --platform web … record stop cycle produces a valid, non-empty, finalized .webm — verified by ffprobe (duration > 0 and a real video stream), not merely file existence — and demonstrably using the managed ffmpeg.
agent-device web doctor flags both a missing ffmpeg and a broken/incapable one (e.g. present but lacking libvpx/VP8) with a clear message.
- If the skip-download opt-out is implemented, a test covers the system-ffmpeg fallback path.
References
Notes: line references are against the current main; the managed backend currently pins agent-browser 0.27.1.
Background
Web screen recording landed in v0.18.0 (#885, #891). The commands are:
agent-device record start <path> --platform webagent-device record stopOutput is a
.webmfile (extension-enforced: non-.webmpaths are rejected). Unlike Android (whereadb screenrecordencodes on-device), the web path has no device to encode on: the managed agent-browser backend polls CDPPage.captureScreenshotat a fixed frame rate and pipes those frames to a system/PATHffmpegthat encodes the webm host-side (VP8/libvpx). The shell-out is a bareCommand::new("ffmpeg")in agent-browser'scli/src/native/recording.rs— no bundled binary and no path/env override — so ffmpeg is a hard runtime dependency of web recording.Problem
agent-device web setupinstalls the managed agent-browser/Chromium backend, but it does NOT install ffmpeg. On a runner without a system ffmpeg, recording fails — and the failure surfaces onrecord stop, notrecord start, becauserecord startlaunches the encoder detached and returns success; the spawn error (ENOENT) is only collected whenrecord stopjoins it:Two issues:
web setupdoes not resolve the error, because setup does not install ffmpeg.actions/runner-imagesUbuntu2404 "Installed Software" manifest), so a headless CI recording use case has to add a separate step (e.g.apt-get install ffmpeg) — friction the tool could remove, the same way it already provisions the browser.Proposed solution
Provision the encoder alongside the managed backend, the way Playwright ships its own ffmpeg during
playwright install. The whole fix can live in agent-device — no agent-browser code change is required.PATH(primary fix, self-contained). On--platform web, agent-device already spawns the pinned agent-browser CLI with a controlled environment —managedAgentBrowserEnv()insrc/platforms/web/agent-browser-tool.tsreturns{ ...process.env, HOME, AGENT_BROWSER_SOCKET_DIR }, andrecord startruns through that env. Prepend a managed-ffmpegbindir toPATHthere. Because agent-browser invokes a bareCommand::new("ffmpeg")that inherits its processPATH, the ffmpeg grandchild then resolves the managed binary — with no change in agent-browser.web setup. Hook intosetupManagedAgentBrowser()(the same flow that installs the browser) to fetch a pinned, per-platform static ffmpeg (built with libvpx/VP8) into the managed backend dir.web doctor. ExtenddoctorManagedAgentBrowser()to probe managed-then-system ffmpeg and verify it can actually encode VP8/webm (not just print-version), reporting presence/version/capability clearly.PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD) that skips the managed ffmpeg and falls back to a system/PATHffmpeg.Optional hardening (not required): an ffmpeg-path env override in agent-browser would make discovery explicit (immune to
PATHorder / a stray earlier system ffmpeg). It is redundant for correctness oncePATHinjection is in place, so it should be a follow-up rather than on the critical path.Acceptance criteria
! command -v ffmpegfirst), afteragent-device web setup, anagent-device record start --platform web…record stopcycle produces a valid, non-empty, finalized.webm— verified byffprobe(duration > 0 and a real video stream), not merely file existence — and demonstrably using the managed ffmpeg.agent-device web doctorflags both a missing ffmpeg and a broken/incapable one (e.g. present but lacking libvpx/VP8) with a clear message.References
--platform web(agent-browser supports.webm, not surfaced by agent-device) #885 (web screen recording request), feat: expose web screen recording #891 (implementation, merged in v0.18.0).playwright install(into thems-playwrightcache; skippable viaPLAYWRIGHT_SKIP_BROWSER_DOWNLOAD), falling back to aPATHffmpeg.vercel-labs/agent-browser(cli/src/native/recording.rs,Command::new("ffmpeg"));agent-device web setup/web doctor(src/cli/commands/web.ts) provision the backend but not ffmpeg.Notes: line references are against the current
main; the managed backend currently pins agent-browser0.27.1.