frame proof, HTML frames, screenshots, recording, PR proof, e2e evidence, validate visually. Daytona artifacts workflow for validated screenshots and optional videos.
npx skills add https://github.com/Devin-AXIS/iPolloWork --skill daytona-recording-artifacts
Use this skill to collect proof that a Daytona UI flow works.
Use daytona-flow-validator before declaring the flow passed. If the user asks
to do e2e tests for a feature, frame proof is required unless they explicitly
ask for non-UI or mock-only validation.
The default proof format is a browseable HTML page with named PNG screenshots
for each step of the flow. This is faster to produce, easier to review, and
works on any device.
Use video (MP4) only when the proof requires motion: streaming text, loading
spinners, animations, drag-and-drop, or real-time interactions that a static
frame cannot capture. When video is used, embed it inside the frame-by-frame
HTML page alongside the static frames.
When a coded eval exists, prefer the eval runner frame output first:
pnpm evals --flow <flow-id> --cdp-url <printed-electron-cdp-url>
The runner writes evals/results/<run-id>/index.html plus validated PNG evidence
from ctx.prove(...) and ctx.screenshot(...). Serve or copy that result
directory for PR evidence.
daytona exec "$SANDBOX" -- 'bash -lc "mkdir -p /workspace/proof-frames; nohup python3 -m http.server 8090 --directory /workspace/proof-frames >/dev/null 2>&1 &"'
browser_screenshot locally and uploadit to the sandbox with a numbered name like 01-auth-landing.png,
02-org-filled.png, etc.
index.html with all frames as labeled images in aresponsive grid. Include the branch, commit, and sandbox name.
FRAMES_URL=$(daytona preview-url "$SANDBOX" -p 8090 2>/dev/null | grep -v "^time=")
echo "${FRAMES_URL}/index.html"
linkable: ${FRAMES_URL}/01-auth-landing.png.
/daytona-artifacts is unavailableThe preferred path is test-on-daytona.sh --artifacts-volume, which mounts and
serves /daytona-artifacts. If that path is unavailable or not writable, do not
stop at local screenshots. Use /workspace/proof-frames as a fallback:
daytona exec "$SANDBOX" -- 'bash -lc "mkdir -p /workspace/proof-frames; nohup python3 -m http.server 8090 --bind 0.0.0.0 --directory /workspace/proof-frames >/tmp/proof-frames-http.log 2>&1 &"'
Upload the generated index.html and PNG frames there, then verify every file is
non-zero before sharing:
daytona exec "$SANDBOX" -- 'bash -lc "ls -lh /workspace/proof-frames && curl -s -I http://127.0.0.1:8090/index.html | sed -n \"1,8p\""'
daytona preview-url "$SANDBOX" -p 8090
If you use this fallback, say so in the PR/eval report because the files are not
on the persistent artifacts volume.
Embed short MP4 clips in the same proof directory when the step involves:
Reference them from the HTML index alongside the static frames.
A useful Daytona recording should look like a person using the product, even
though CDP is driving the browser or Electron window.
browser_snapshot, browser_click, and browser_fill wherever possible.The reusable Daytona volume is:
ipollowork-eval-artifacts:/daytona-artifacts
The helper serves it on port 8090 when --artifacts-volume or
--record-video is used.
Expected layout:
/daytona-artifacts/recordings
/daytona-artifacts/screenshots
/daytona-artifacts/validation
For screenshots and validation notes without video:
bash .devcontainer/test-on-daytona.sh [branch-or-commit] --artifacts-volume
For full human-review evidence:
bash .devcontainer/test-on-daytona.sh [branch-or-commit] --record-video --recording-name <name>
--record-video implies --artifacts-volume.
Capture a persistent screenshot from the Daytona display:
daytona exec "$SANDBOX" -- 'bash .devcontainer/capture-daytona-screenshot.sh'
Use this after important states: welcome screen, workspace created, settings
connected, task response visible, error state reproduced, or final success.
Before sharing any screenshot URL, follow daytona-flow-validator and inspect
the saved PNG itself. Confirm the visible image shows the claimed state and is
not covered by a native picker, modal, toast, desktop window, or unrelated
overlay. If the screenshot does not match, recapture and inspect a replacement.
Always stop with the helper so ffmpeg finalizes the MP4 cleanly:
daytona exec "$SANDBOX" -- 'bash .devcontainer/stop-daytona-recording.sh'
Do not use kill -9; it can corrupt the file.
After stopping, verify the recording exists and has duration:
daytona exec "$SANDBOX" -- 'ls -lh /daytona-artifacts/recordings'
daytona exec "$SANDBOX" -- 'ffprobe -v error -show_entries format=duration -of default=nw=1:nk=1 /daytona-artifacts/recordings/<name>.mp4'
If the duration is near zero, missing, or the file is absent, the recording is
not usable evidence.
Get the artifacts base URL:
ARTIFACTS_URL=$(daytona preview-url "$SANDBOX" -p 8090 2>/dev/null | grep -v "^time=")
Then append paths:
echo "${ARTIFACTS_URL}/recordings/<name>.mp4"
echo "${ARTIFACTS_URL}/screenshots/<name>.png"
Artifact proxy URLs are not permanent. If the sandbox stops, the old
daytonaproxy URL will fail even when files still exist in
/daytona-artifacts. Restart the sandbox and artifact server, then generate a
fresh URL:
daytona sandbox start "$SANDBOX"
daytona exec "$SANDBOX" -- 'bash -lc '\''cd /daytona-artifacts && nohup python3 -m http.server 8090 --bind 0.0.0.0 > /tmp/daytona-artifacts-http.log 2>&1 &'\'''
daytona exec "$SANDBOX" -- 'curl -s -I http://127.0.0.1:8090/recordings/<name>.mp4 | sed -n "1,8p"'
daytona preview-url "$SANDBOX" -p 8090
Only share the refreshed URL after the local curl -I returns 200 OK with a
non-zero Content-Length.
Use before/after recordings for UI regressions or design changes:
bash .devcontainer/test-on-daytona.sh dev --record-video --recording-name my-feature-before
daytona exec "$SANDBOX" -- 'bash .devcontainer/stop-daytona-recording.sh'
daytona exec "$SANDBOX" -- "bash -lc 'cd /workspace && git fetch origin feat/my-branch:feat/my-branch && git checkout feat/my-branch'"
daytona exec "$SANDBOX" -- "bash -lc 'cd /workspace && DISPLAY=:99 .devcontainer/start-daytona-recording.sh --detach --output /daytona-artifacts/recordings/my-feature-after.mp4'"
daytona exec "$SANDBOX" -- 'bash .devcontainer/stop-daytona-recording.sh'
Use these layers in order of priority:
This is the primary evidence format for UI flows.
process state alongside each frame capture.
steps that require motion proof (streaming, animations, loading states).
Do not report success from a recording alone. The AI should inspect state with
browser tools and use screenshots to validate visible behavior before declaring
the flow passed.
Do not use a video as the primary demo if most of the flow happened through
hidden automation. In that case, mark the run as technical validation only and
produce a new frame-by-frame proof for human review.
If you discover invalid evidence after the fact, do not reuse the same URL as
if it were valid. Produce new frames with new names and explain in the
PR/comment that the earlier artifact was superseded.
Take devin-axis/daytona-recording-artifacts from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.