VM Lab Use this when the task needs a clean macOS VM to test GUI automation, TCC prompts, screenshot capture, clicking, typing, performance, or "two-way validation" of Peekaboo-like tools. Core idea: run the tool under test inside the guest, but verify it from outside the guest with Parallels screenshots and host-side observations. Do not close apps you do not own. Safety Rules - Treat the VM snapshot as disposable, not the host. - Never print secrets. If is needed, follow the 1Password skill and run it only inside . - Prefer fresh app windows you create yourself: TextEdit, a local HTML test…

./r\\n'\n```\n\nAvoid long command typing. Parallels key injection uses its own key-code table and can be layout-sensitive.\n\n## Known Pitfalls\n\n- macOS clipboard APIs may fail from `prlctl exec`; `pbcopy`, AppleScript clipboard, and Peekaboo paste can all fail in headless guest context.\n- `open -na Ghostty.app --args -e ...` may only focus an existing Ghostty window on macOS; do not assume it runs the command.\n- `prlctl exec` may re-join argv through a guest shell; for complex payloads, pass one fully shell-quoted command string or create the file with a tiny Python writer.\n- Parallels `send-key-event --key` uses Parallels key values, not macOS virtual key codes.\n- For normal typing, send `prlctl send-key-event \u003cvm> --key \u003ckey>` with no `--event`; explicit `press`/`release` can repeat or stick. Return is an exception: use press then release.\n- Prefer one `prlctl send-key-event --json` batch over many separate `send-key-event` processes; separate calls can drift under focus/latency.\n- Use `PRL_KEY_ENTER = 36`, `PRL_KEY_SLASH = 61`, `PRL_KEY_R = 27`, `PRL_KEY_T = 28`, `PRL_KEY_M = 58`, `PRL_KEY_P = 33`.\n- If keystrokes produce garbage, send Return to clear the line, create a shorter launcher, then retry.\n- If Peekaboo permission probes hang with Screen Recording missing and emit `SWIFT TASK CONTINUATION MISUSE`, record it as a product bug; do not confuse it with the VM harness.\n\n## Two-Way Validation\n\nFor each GUI action, verify through two independent signals:\n\n- Tool-under-test output: JSON, screenshot file, AX result, or app state.\n- External verifier: `prlctl capture`, host-side image inspection, file content in guest, or process/window state.\n\nExamples:\n\n- Screenshot: compare Peekaboo image dimensions/content against `prlctl capture`.\n- Click: use Peekaboo to click a test button, then verify both guest app state and host screenshot.\n- Type: use Peekaboo to type into a controlled text field, then verify AX value and host screenshot.\n- Performance: wrap commands with `/usr/bin/time -p`; repeat cold/warm runs; keep outputs in `/tmp`.\n\n## Peekaboo VM Baseline\n\nInside guest:\n\n```bash\ncd ~/Projects/Peekaboo\ngit pull --recurse-submodules\nswift build --package-path Apps/CLI\nApps/CLI/.build/debug/peekaboo --version\nApps/CLI/.build/debug/peekaboo permissions status --json\n```\n\nHost-side reference capture:\n\n```bash\nprlctl capture \"macOS Tahoe\" --file /tmp/vm-prlctl-reference.png\n```\n\nGuest-side Peekaboo capture through Ghostty:\n\n```bash\n/tmp/r\n```\n\nCompare:\n\n```bash\nprlctl exec \"macOS Tahoe\" \\\n 'sudo -u steipete -H /bin/zsh -lc '\\''sips -g pixelWidth -g pixelHeight /tmp/peekaboo-vm.png'\\'''\nsips -g pixelWidth -g pixelHeight /tmp/vm-prlctl-reference.png\n```\n\n## Reporting\n\nWhen handing off, include only:\n\n- VM name and OS build.\n- repo commit tested.\n- permission state.\n- commands that passed/failed.\n- independent verifier result.\n- product bugs discovered.\n---","attachment_filenames":["agents/openai.yaml","scripts/parallels_type.py"],"attachments":[{"filename":"agents/openai.yaml","content":"interface:\n display_name: \"VM Lab\"\n short_description: \"Verify macOS GUI automation in VM labs\"\n default_prompt: \"Use $vm-lab to run GUI automation under real TCC permissions, verify it with independent host screenshots, and report only actionable results.\"\n","content_type":"application/yaml; charset=utf-8","language":"yaml","size":261,"content_sha256":"07cbd0894550b8c12b64f8fc5e059d69ae57ff32e0b1e30fa654906ce4a73f86"},{"filename":"scripts/parallels_type.py","content":"#!/usr/bin/env python3\n\"\"\"Type a short US-keyboard string into a Parallels VM via prlctl.\n\nUse this only for short launchers such as \"/tmp/r\\n\". For long commands,\nwrite a script inside the guest first and type the short path.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport json\nimport subprocess\nimport sys\nimport time\n\n\nKEYS = {\n \"1\": 10,\n \"2\": 11,\n \"3\": 12,\n \"4\": 13,\n \"5\": 14,\n \"6\": 15,\n \"7\": 16,\n \"8\": 17,\n \"9\": 18,\n \"0\": 19,\n \"-\": 20,\n \"q\": 24,\n \"w\": 25,\n \"e\": 26,\n \"r\": 27,\n \"t\": 28,\n \"y\": 29,\n \"u\": 30,\n \"i\": 31,\n \"o\": 32,\n \"p\": 33,\n \"a\": 38,\n \"s\": 39,\n \"d\": 40,\n \"f\": 41,\n \"g\": 42,\n \"h\": 43,\n \"j\": 44,\n \"k\": 45,\n \"l\": 46,\n \"z\": 52,\n \"x\": 53,\n \"c\": 54,\n \"v\": 55,\n \"b\": 56,\n \"n\": 57,\n \"m\": 58,\n \",\": 59,\n \".\": 60,\n \"/\": 61,\n \" \": 65,\n \"\\n\": 36,\n}\n\n\nSHIFT_KEYS = {\n \"_\": 20,\n \":\": 47,\n '\"': 48,\n \"?\": 61,\n}\n\n\ndef append_key(events: list[dict[str, int | str | float]], key: int, delay_ms: int) -> None:\n if key == 36:\n events.append({\"key\": key, \"event\": \"press\", \"delay\": delay_ms})\n events.append({\"key\": key, \"event\": \"release\", \"delay\": delay_ms})\n return\n\n events.append({\"key\": key, \"delay\": delay_ms})\n\n\ndef append_shift_key(events: list[dict[str, int | str | float]], key: int, delay_ms: int) -> None:\n events.append({\"key\": 50, \"event\": \"press\", \"delay\": delay_ms})\n append_key(events, key, delay_ms)\n events.append({\"key\": 50, \"event\": \"release\", \"delay\": delay_ms})\n\n\ndef main() -> int:\n parser = argparse.ArgumentParser(description=__doc__)\n parser.add_argument(\"vm\", help=\"Parallels VM name or UUID\")\n parser.add_argument(\"text\", help=\"Text to type. Use

VM Lab Use this when the task needs a clean macOS VM to test GUI automation, TCC prompts, screenshot capture, clicking, typing, performance, or "two-way validation" of Peekaboo-like tools. Core idea: run the tool under test inside the guest, but verify it from outside the guest with Parallels screenshots and host-side observations. Do not close apps you do not own. Safety Rules - Treat the VM snapshot as disposable, not the host. - Never print secrets. If is needed, follow the 1Password skill and run it only inside . - Prefer fresh app windows you create yourself: TextEdit, a local HTML test…

...\\\\n' from zsh for Return.\")\n parser.add_argument(\"--delay\", type=float, default=0.08, help=\"Delay between keys in seconds\")\n parser.add_argument(\"--focus-app\", help=\"Guest app to focus first, e.g. Ghostty\")\n args = parser.parse_args()\n\n if args.focus_app:\n subprocess.run(\n [\"prlctl\", \"exec\", args.vm, f\"sudo -u steipete -H open -a {args.focus_app!r}\"],\n check=False,\n stdout=subprocess.DEVNULL,\n stderr=subprocess.DEVNULL,\n )\n time.sleep(0.5)\n\n delay_ms = int(args.delay * 1000)\n events: list[dict[str, int | str | float]] = []\n\n for char in args.text:\n lower = char.lower()\n if char in SHIFT_KEYS:\n append_shift_key(events, SHIFT_KEYS[char], delay_ms)\n elif lower in KEYS and char == lower:\n append_key(events, KEYS[char], delay_ms)\n elif lower in KEYS and char != lower:\n append_shift_key(events, KEYS[lower], delay_ms)\n else:\n print(f\"unsupported character: {char!r}\", file=sys.stderr)\n return 2\n\n subprocess.run(\n [\"prlctl\", \"send-key-event\", args.vm, \"--json\"],\n input=json.dumps(events).encode(),\n check=True,\n stdout=subprocess.DEVNULL,\n )\n return 0\n\n\nif __name__ == \"__main__\":\n raise SystemExit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":3106,"content_sha256":"3af61e47aec432f86f6554f5f5cd2ef29c34e3fc1a87243efa98bb49bdd26a1b"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"VM Lab","type":"text"}]},{"type":"paragraph","content":[{"text":"Use this when the task needs a clean macOS VM to test GUI automation, TCC prompts, screenshot capture, clicking, typing, performance, or \"two-way validation\" of Peekaboo-like tools.","type":"text"}]},{"type":"paragraph","content":[{"text":"Core idea: run the tool under test inside the guest, but verify it from outside the guest with Parallels screenshots and host-side observations. Do not close apps you do not own.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Safety Rules","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Treat the VM snapshot as disposable, not the host.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Never print secrets. If ","type":"text"},{"text":"op","type":"text","marks":[{"type":"code_inline"}]},{"text":" is needed, follow the 1Password skill and run it only inside ","type":"text"},{"text":"tmux","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Prefer fresh app windows you create yourself: TextEdit, a local HTML test page, or a small test app.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Avoid modifying host state except temporary screenshots under ","type":"text"},{"text":"/tmp","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For git repos inside the VM, use HTTPS remotes and normal branch discipline.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"VM Discovery","type":"text"}]},{"type":"paragraph","content":[{"text":"List VMs:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"prlctl list --all","type":"text"}]},{"type":"paragraph","content":[{"text":"Get VM status/IP:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"prlctl list --info \"macOS Tahoe\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Run guest commands as Peter:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"prlctl exec \"macOS Tahoe\" \\\n 'sudo -u steipete -H /bin/zsh -lc '\\''source ~/.zprofile 2>/dev/null || true; uname -a'\\'''","type":"text"}]},{"type":"paragraph","content":[{"text":"Capture an independent host-side screenshot:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"prlctl capture \"macOS Tahoe\" --file /tmp/vm-reference.png\nsips -g pixelWidth -g pixelHeight /tmp/vm-reference.png","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"TCC / GUI Attribution","type":"text"}]},{"type":"paragraph","content":[{"text":"For macOS Screen Recording and Accessibility, the responsible process matters.","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"prlctl exec","type":"text","marks":[{"type":"code_inline"}]},{"text":" is headless and can fail to produce useful Screen Recording attribution.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Launch the test command from a visible terminal app in the guest when Screen Recording is involved.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ghostty works as a GUI terminal if installed.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"After a first failed capture, check ","type":"text"},{"text":"System Settings > Privacy & Security > Screen & System Audio Recording","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"permissions status","type":"text","marks":[{"type":"code_inline"}]},{"text":" run through ","type":"text"},{"text":"prlctl exec","type":"text","marks":[{"type":"code_inline"}]},{"text":" may still report Screen Recording false after Ghostty is allowed; validate Screen Recording by rerunning the capture from Ghostty.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Open the Screen Recording pane:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"prlctl exec \"macOS Tahoe\" \\\n 'sudo -u steipete -H open \"x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture\"'","type":"text"}]},{"type":"paragraph","content":[{"text":"Open Ghostty:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"prlctl exec \"macOS Tahoe\" 'sudo -u steipete -H open -a Ghostty'","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Running Commands Through Ghostty","type":"text"}]},{"type":"paragraph","content":[{"text":"Best path: create a guest script with ","type":"text"},{"text":"prlctl exec","type":"text","marks":[{"type":"code_inline"}]},{"text":", open/focus Ghostty, then type only a short launcher path into the visible terminal.","type":"text"}]},{"type":"paragraph","content":[{"text":"Guest script pattern:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"prlctl exec \"macOS Tahoe\" 'sudo -u steipete -H /bin/zsh -lc '\\''cat > /tmp/run-vm-lab.zsh \u003c\u003cEOF\n#!/bin/zsh\nsource ~/.zprofile 2>/dev/null || true\ncd ~/Projects/Peekaboo || exit 1\nApps/CLI/.build/debug/peekaboo image --path /tmp/peekaboo-vm.png --json\nrc=$?\necho \"EXIT:$rc\"\n[ -f /tmp/peekaboo-vm.png ] && sips -g pixelWidth -g pixelHeight /tmp/peekaboo-vm.png\necho \"Press return to close...\"\nread _\nexit $rc\nEOF\nchmod +x /tmp/run-vm-lab.zsh\nln -sf /tmp/run-vm-lab.zsh /tmp/r\nopen -a Ghostty'\\'''","type":"text"}]},{"type":"paragraph","content":[{"text":"Then link the launcher into Ghostty's home directory and type ","type":"text"},{"text":"./r","type":"text","marks":[{"type":"code_inline"}]},{"text":" with ","type":"text"},{"text":"scripts/parallels_type.py","type":"text","marks":[{"type":"code_inline"}]},{"text":". This avoids unreliable path characters in Parallels key injection.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"prlctl exec \"macOS Tahoe\" \\\n \"sudo -u steipete -H /bin/zsh -lc 'ln -sf /tmp/run-vm-lab.zsh ~/r'\"\npython3 skills/vm-lab/scripts/parallels_type.py \"macOS Tahoe\"

VM Lab Use this when the task needs a clean macOS VM to test GUI automation, TCC prompts, screenshot capture, clicking, typing, performance, or "two-way validation" of Peekaboo-like tools. Core idea: run the tool under test inside the guest, but verify it from outside the guest with Parallels screenshots and host-side observations. Do not close apps you do not own. Safety Rules - Treat the VM snapshot as disposable, not the host. - Never print secrets. If is needed, follow the 1Password skill and run it only inside . - Prefer fresh app windows you create yourself: TextEdit, a local HTML test…

./r\\n'","type":"text"}]},{"type":"paragraph","content":[{"text":"Avoid long command typing. Parallels key injection uses its own key-code table and can be layout-sensitive.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Known Pitfalls","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"macOS clipboard APIs may fail from ","type":"text"},{"text":"prlctl exec","type":"text","marks":[{"type":"code_inline"}]},{"text":"; ","type":"text"},{"text":"pbcopy","type":"text","marks":[{"type":"code_inline"}]},{"text":", AppleScript clipboard, and Peekaboo paste can all fail in headless guest context.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"open -na Ghostty.app --args -e ...","type":"text","marks":[{"type":"code_inline"}]},{"text":" may only focus an existing Ghostty window on macOS; do not assume it runs the command.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"prlctl exec","type":"text","marks":[{"type":"code_inline"}]},{"text":" may re-join argv through a guest shell; for complex payloads, pass one fully shell-quoted command string or create the file with a tiny Python writer.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Parallels ","type":"text"},{"text":"send-key-event --key","type":"text","marks":[{"type":"code_inline"}]},{"text":" uses Parallels key values, not macOS virtual key codes.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For normal typing, send ","type":"text"},{"text":"prlctl send-key-event \u003cvm> --key \u003ckey>","type":"text","marks":[{"type":"code_inline"}]},{"text":" with no ","type":"text"},{"text":"--event","type":"text","marks":[{"type":"code_inline"}]},{"text":"; explicit ","type":"text"},{"text":"press","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"release","type":"text","marks":[{"type":"code_inline"}]},{"text":" can repeat or stick. Return is an exception: use press then release.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Prefer one ","type":"text"},{"text":"prlctl send-key-event --json","type":"text","marks":[{"type":"code_inline"}]},{"text":" batch over many separate ","type":"text"},{"text":"send-key-event","type":"text","marks":[{"type":"code_inline"}]},{"text":" processes; separate calls can drift under focus/latency.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"PRL_KEY_ENTER = 36","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"PRL_KEY_SLASH = 61","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"PRL_KEY_R = 27","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"PRL_KEY_T = 28","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"PRL_KEY_M = 58","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"PRL_KEY_P = 33","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If keystrokes produce garbage, send Return to clear the line, create a shorter launcher, then retry.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If Peekaboo permission probes hang with Screen Recording missing and emit ","type":"text"},{"text":"SWIFT TASK CONTINUATION MISUSE","type":"text","marks":[{"type":"code_inline"}]},{"text":", record it as a product bug; do not confuse it with the VM harness.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Two-Way Validation","type":"text"}]},{"type":"paragraph","content":[{"text":"For each GUI action, verify through two independent signals:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Tool-under-test output: JSON, screenshot file, AX result, or app state.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"External verifier: ","type":"text"},{"text":"prlctl capture","type":"text","marks":[{"type":"code_inline"}]},{"text":", host-side image inspection, file content in guest, or process/window state.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Examples:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Screenshot: compare Peekaboo image dimensions/content against ","type":"text"},{"text":"prlctl capture","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Click: use Peekaboo to click a test button, then verify both guest app state and host screenshot.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Type: use Peekaboo to type into a controlled text field, then verify AX value and host screenshot.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Performance: wrap commands with ","type":"text"},{"text":"/usr/bin/time -p","type":"text","marks":[{"type":"code_inline"}]},{"text":"; repeat cold/warm runs; keep outputs in ","type":"text"},{"text":"/tmp","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Peekaboo VM Baseline","type":"text"}]},{"type":"paragraph","content":[{"text":"Inside guest:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"cd ~/Projects/Peekaboo\ngit pull --recurse-submodules\nswift build --package-path Apps/CLI\nApps/CLI/.build/debug/peekaboo --version\nApps/CLI/.build/debug/peekaboo permissions status --json","type":"text"}]},{"type":"paragraph","content":[{"text":"Host-side reference capture:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"prlctl capture \"macOS Tahoe\" --file /tmp/vm-prlctl-reference.png","type":"text"}]},{"type":"paragraph","content":[{"text":"Guest-side Peekaboo capture through Ghostty:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"/tmp/r","type":"text"}]},{"type":"paragraph","content":[{"text":"Compare:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"prlctl exec \"macOS Tahoe\" \\\n 'sudo -u steipete -H /bin/zsh -lc '\\''sips -g pixelWidth -g pixelHeight /tmp/peekaboo-vm.png'\\'''\nsips -g pixelWidth -g pixelHeight /tmp/vm-prlctl-reference.png","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Reporting","type":"text"}]},{"type":"paragraph","content":[{"text":"When handing off, include only:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"VM name and OS build.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"repo commit tested.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"permission state.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"commands that passed/failed.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"independent verifier result.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"product bugs discovered.","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"vm-lab","author":"@skillopedia","source":{"stars":4063,"repo_name":"agent-scripts","origin_url":"https://github.com/steipete/agent-scripts/blob/HEAD/skills/vm-lab/SKILL.md","repo_owner":"steipete","body_sha256":"47b71c35b7f6c6e27ab4e11d951096b9fefc5277642ea509e72ebab33b472e50","cluster_key":"77ee35875199c835b33dcc0be75c58c1596e021c5c07e1e15b66af707a5f8bd8","clean_bundle":{"format":"clean-skill-bundle-v1","source":"steipete/agent-scripts/skills/vm-lab/SKILL.md","attachments":[{"id":"cb16dea4-2f7d-5bf1-ac15-a02c8fe7005f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/cb16dea4-2f7d-5bf1-ac15-a02c8fe7005f/attachment.yaml","path":"agents/openai.yaml","size":261,"sha256":"07cbd0894550b8c12b64f8fc5e059d69ae57ff32e0b1e30fa654906ce4a73f86","contentType":"application/yaml; charset=utf-8"},{"id":"c79f4b00-9eae-5cb4-8d15-2bd1a1a75370","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/c79f4b00-9eae-5cb4-8d15-2bd1a1a75370/attachment.py","path":"scripts/parallels_type.py","size":3106,"sha256":"3af61e47aec432f86f6554f5f5cd2ef29c34e3fc1a87243efa98bb49bdd26a1b","contentType":"text/x-python; charset=utf-8"}],"bundle_sha256":"fcbc79fcd9ac30a0f0715b4fb9567e2faf78c3b14524d062d554d76765a5fb63","attachment_count":2,"text_attachments":2,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/vm-lab/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"web-development","category_label":"Web"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"web-development","import_tag":"clean-skills-v1","description":"Parallels macOS VM lab: GUI automation, Peekaboo, TCC, Ghostty."}},"renderedAt":1782986989002}

VM Lab Use this when the task needs a clean macOS VM to test GUI automation, TCC prompts, screenshot capture, clicking, typing, performance, or "two-way validation" of Peekaboo-like tools. Core idea: run the tool under test inside the guest, but verify it from outside the guest with Parallels screenshots and host-side observations. Do not close apps you do not own. Safety Rules - Treat the VM snapshot as disposable, not the host. - Never print secrets. If is needed, follow the 1Password skill and run it only inside . - Prefer fresh app windows you create yourself: TextEdit, a local HTML test…