name: hd-self-screenshot-mac description: > macOS platform companion to hd-self-screenshot — the Apple-specific half of HD screenshotting its own window, PLUS the token-efficient capture flow (shot — one call, prints a PNG path, never floods context with base64). The tool ladder, the POST /screenshot CDP endpoint, selector region-clips, the sharing gate, and the during-a-recording contention matrix live in hd-self-screenshot (adom/hd-bootstrap); THIS skill carries the shot helper doctrine and the macOS capture internals: the screencapture CLI / CoreGraphics window path, the CDP Page.captureScreenshot content grab, how the per-panel selector crop resolves the rect via dom.measure (WKWebView has no CDP) and crops with the image crate, and the Screen Recording TCC grant. Mirror of hd-self-screenshot-windows (Win32 PrintWindow/BitBlt). Trigger words — screenshot hd mac, shot helper, token efficient screenshot, screencapture cli, coregraphics screenshot, wkwebview no cdp, dom.measure crop, page.capturescreenshot mac, screen recording permission screenshot, tcc screenshot grant.

hd-self-screenshot (macOS) — screencapture / CoreGraphics + the CDP content path

This is the macOS half of hd-self-screenshot. The default flow — adom-cli hydrogen screenshot panel|workspace|screen saving a PNG into the container's screenshots/ to Read, the POST /screenshot {target,selector,b64,silent} CDP power-path, the sharing gate, and the multi-thread capture_busy / coexistence matrix — is cross-platform and lives in the generic hd-self-screenshot skill. Read that first; this skill documents the token-efficient capture flow and what's Apple-specific about how the bytes are grabbed.

⭐ ALWAYS capture with shot — 2 tool calls, ~20 bytes of output

Never run adom-cli hydrogen screenshot ... bare. It prints the capture as a ~300 KB base64 dataUrl JSON on stdout — that's ~85k tokens of noise in your context per capture, plus a second decode step you'd have to improvise. This bootstrap installs a wrapper that does the whole thing in one call and prints ONLY the PNG path:

shot                        # whole workspace (all panels)  → /tmp/shot-workspace-<ts>.png
shot screen                 # entire screen (desktop, other apps)
shot panel --name "KiCad"   # one panel's content
shot workspace --reason "verify the flow viewer rendered"   # flags pass through

Then Read the printed path — the Read tool attaches images efficiently. Total flow: one Bash call + one Read. That's the floor; don't add steps.

  • If no image comes back, shot exits 1 and prints the CLI's own JSON to stderr — usually the sharing gate (capture needs the user's sharing approval; pass --reason "…" so the approval dialog says why). Read the error, don't blind-retry.
  • SHOT_OUT=/path/out.png shot ... overrides the output path if you need a stable name.
  • If shot is missing (pre-0.1.3 workspace), re-converge: adom-wiki pkg install adom/hd-mac-bootstrap — or inline the same pipe: adom-cli hydrogen screenshot workspace 2>/dev/null | python3 -c "import sys,json,base64;d=json.load(sys.stdin);open('/tmp/ws.png','wb').write(base64.b64decode(d['dataUrl'].split(',',1)[1]));print('/tmp/ws.png')"

How HD grabs its own window on macOS

  • Whole-window / desktop: HD uses the macOS screencapture CLI (and CoreGraphics window capture) to grab the HD window or the full screen — the macOS analog of the Windows PrintWindow/BitBlt path.
  • Webview / panel content: the canonical content grab is CDP Page.captureScreenshot (the /capture/viewport · /shot path) — a one-shot, wake-lock-free capture of the rendered surface. This is the same POST /screenshot endpoint as everywhere; on macOS it backs the target/panel content capture.

⭐ The per-panel selector crop — dom.measure, not CDP

On Windows the selector region-clip can lean on CDP against the webview. On macOS the HD shell uses WKWebView, which exposes no CDP to drive the page directly. So a per-panel / per-selector crop resolves the rect a different way:

  1. Resolve the element's rectangle via the dom.measure ui-action RPC (the UI-command bus measures the selector in the live DOM and returns its bounds).
  2. Capture the content area (CDP Page.captureScreenshot / screencapture).
  3. Crop the captured image to that rect with the Rust image crate.

So {selector:".resource-bars"} still clips to just that element — but the rect comes from dom.measure and the crop is server-side in Rust, because WKWebView can't be CDP-shot to a selector the way a Chromium webview can.

macOS gotcha — the Screen Recording TCC grant

The OS-level capture (screencapture / CoreGraphics) is gated by macOS TCC: System Settings → Privacy & Security → Screen Recording must allow Hydrogen Desktop. Without that grant a window/screen capture comes back black or empty even though the call "succeeds." If screenshots are blank, check the Screen Recording grant first — it's the same grant the desktop recording paths need ([hd-recording-mac]).

NOT here (lives in the Windows companion)

The Win32 capture primitives — PrintWindow (per-window, works for backgrounded windows) and BitBlt — are the Windows self-screenshot mechanics; see hd-self-screenshot-windows. On macOS it's screencapture/CoreGraphics + CDP Page.captureScreenshot, with dom.measure-driven cropping for selectors.