harness:screenshot
Workflow
Do you want a quick one-shot capture? → Run the CLI
Do you want to embed captures inside an agent pipeline? → Programmatic usage
Do you want Claude to decide when to capture? → Agent-driven capture
Overview
The screenshot skill captures the visual state of a running application and saves it as a timestamped PNG artifact. It supports three capture backends, selected automatically based on what is available:
| Backend | Target | Dependency |
|---|---|---|
playwright |
Browser pages (Chromium / Firefox / WebKit) | playwright Python package |
pillow |
Full desktop or specific window (X11 / macOS / Win) | Pillow + python-xlib or pygetwindow |
terminal |
Terminal / CLI output rendered to image | Pillow + pyte |
All backends produce the same output shape — a ScreenshotArtifact — so the
rest of the pipeline never needs to know which backend ran.
CLI Usage
# Capture a browser page at a URL:
python skills/screenshot/scripts/capture_screenshot.py \
--url http://localhost:3000 \
--out .artifacts/screenshots/
# Capture the full desktop:
python skills/screenshot/scripts/capture_screenshot.py \
--desktop \
--out .artifacts/screenshots/
# Capture and print base64 to stdout (for inline embedding):
python skills/screenshot/scripts/capture_screenshot.py \
--url http://localhost:3000 \
--base64
# Capture with a label (embedded in filename and metadata):
python skills/screenshot/scripts/capture_screenshot.py \
--url http://localhost:3000 \
--label "after-nav-refactor" \
--out .artifacts/screenshots/
# Capture a specific viewport size:
python skills/screenshot/scripts/capture_screenshot.py \
--url http://localhost:3000 \
--width 1280 \
--height 800 \
--out .artifacts/screenshots/
# Wait for a CSS selector to appear before capturing:
python skills/screenshot/scripts/capture_screenshot.py \
--url http://localhost:3000 \
--wait-for "#app.ready" \
--out .artifacts/screenshots/
Programmatic Usage
1 — Simple browser capture
from harness_skills.screenshot import capture_url, ScreenshotOptions
artifact = capture_url(
url="http://localhost:3000",
options=ScreenshotOptions(width=1280, height=800, label="home-page"),
out_dir=".artifacts/screenshots/",
)
print(artifact.path) # PosixPath('.artifacts/screenshots/home-page_2026-03-20T….png')
print(artifact.label) # "home-page"
print(artifact.timestamp) # datetime(2026, 3, 20, …, tzinfo=UTC)
print(artifact.size_bytes) # 84320
2 — Desktop / window capture
from harness_skills.screenshot import capture_desktop, capture_window
# Full desktop:
artifact = capture_desktop(out_dir=".artifacts/screenshots/")
# Specific window by title substring:
artifact = capture_window(title="My App", out_dir=".artifacts/screenshots/")
3 — Base64 inline artifact (no file written)
from harness_skills.screenshot import capture_url_base64
b64 = capture_url_base64("http://localhost:3000")
# Embed in an agent message, a bug report, or an HTML page:
html = f'<img src="data:image/png;base64,{b64}" />'
4 — Sequence capture (before / after)
from harness_skills.screenshot import SequenceCapture
with SequenceCapture(label="nav-refactor", out_dir=".artifacts/screenshots/") as seq:
before = seq.snap("before", url="http://localhost:3000/nav")
# … apply code change or trigger action …
after = seq.snap("after", url="http://localhost:3000/nav")
print(seq.diff_summary()) # {"before": "…", "after": "…", "size_delta_bytes": -1240}
Agent-Driven Capture
Wire screenshot_tool into a Claude agent session so Claude can decide when to
take a screenshot:
import asyncio
from harness_skills.screenshot_agent import build_screenshot_tools, run_screenshot_agent
from claude_agent_sdk import ClaudeAgentOptions
# Build an MCP server exposing the screenshot tool to Claude:
server = build_screenshot_tools(out_dir=".artifacts/screenshots/")
options = ClaudeAgentOptions(
mcp_servers={"screenshot": server},
allowed_tools=["take_screenshot", "list_screenshots"],
)
# Or let run_screenshot_agent manage the full session:
result = asyncio.run(
run_screenshot_agent(
prompt="Take a screenshot of http://localhost:3000 before and after clicking the login button.",
out_dir=".artifacts/screenshots/",
model="claude-opus-4-6",
max_turns=8,
)
)
print(result)
MCP Tools exposed to Claude
| Tool | Description |
|---|---|
take_screenshot |
Captures a URL, desktop, or window. Accepts url, label, width, height, wait_for, desktop (bool). Returns ScreenshotArtifact JSON. |
list_screenshots |
Lists all PNG artifacts in out_dir with metadata (label, timestamp, size). |
Output Artifact
Every capture returns a ScreenshotArtifact:
@dataclass
class ScreenshotArtifact:
path: Path # Absolute path to the saved PNG (None if base64-only)
filename: str # e.g. "home-page_2026-03-20T14-05-33Z.png"
label: str # Human-readable label (from --label or auto-generated)
timestamp: datetime # UTC capture time
size_bytes: int # File size in bytes (0 if base64-only)
backend: str # "playwright" | "pillow" | "terminal"
base64: str | None # Populated only when base64 mode is requested
metadata: dict # url, viewport, window_title, etc.
Artifacts are written to out_dir (default: .artifacts/screenshots/) with the
naming pattern:
{label}_{ISO-8601-timestamp}.png
where timestamp colons are replaced with hyphens for filesystem compatibility.
Backend Detection & Fallback
The capture functions probe available backends at import time:
playwright— preferred for URL captures; falls back topillowif not installed.pillow— used for desktop / window captures; required for terminal captures.terminal— activated only when--terminal/capture_terminal()is called.
Install the recommended extras:
# Browser capture:
uv add playwright && playwright install chromium
# Desktop capture (Linux/X11):
uv add Pillow python-xlib
# Desktop capture (macOS / Windows):
uv add Pillow pygetwindow
# Terminal-to-image:
uv add Pillow pyte
Key Files
| Path | Purpose |
|---|---|
harness_skills/screenshot.py |
Core capture logic — ScreenshotArtifact, ScreenshotOptions, SequenceCapture, all capture_* helpers. |
harness_skills/screenshot_agent.py |
Agent SDK interface — build_screenshot_tools, run_screenshot_agent, MCP tool definitions. |
skills/screenshot/scripts/capture_screenshot.py |
Standalone CLI helper; runs without installing the package. |