[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M7188V4XC9FE2A48R1F8EBJM":3,"skill-same:01M7188V4XC9FE2A48R1F8EBJM":58},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":31,"linkOnly":32,"markdownContent":33,"markdownBody":34,"frontMatter":35,"refName":36,"commitSha":37,"skillDirectory":38,"forksCount":39,"repositoryHtmlUrl":40,"repositoryHomepageUrl":6,"ownerHtmlUrl":41,"ownerBlogUrl":42,"ownerDescription":6,"updatedAt":43,"install":44,"resources":57},"01M7188V4XC9FE2A48R1F8EBJM","verify",null,"Build the computer-use-demo image and drive the Streamlit UI headlessly to verify changes end-to-end.","anthropics\u002Fclaude-quickstarts","anthropics","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F76263028?v=4","01M697XGDPXJAVQ8391V2BCYTE","Anthropic","01M7188R62QSTJZJJ3DFX7XFT5",20808,"MIT","https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fclaude-quickstarts\u002Fblob\u002Fmain\u002Fcomputer-use-demo\u002F.claude\u002Fskills\u002Fverify\u002FSKILL.md",[],[5,19,20,21,22,23,24,25,26,27,28,29,30],"changes","build","Verify Changes","end","use","ui","image","streamlit","drive","computer-use","computer","demo","2026-11-10 10:12:30",false,"---\nname: verify\ndescription: Build the computer-use-demo image and drive the Streamlit UI headlessly to verify changes end-to-end.\n---\n\n# Verifying changes to this demo\n\nThe surface is the Streamlit app inside the container. Build the image from this directory, run it, and drive the UI with Playwright. `pytest`, `ruff`, and `pyright` are CI's job, not evidence.\n\n## Build and run\n\n```sh\ndocker build . -t computer-use-demo:verify\ndocker rm -f cu-verify 2>\u002Fdev\u002Fnull\ndocker run -d --name cu-verify \\\n  -e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY -e WIDTH=1024 -e HEIGHT=768 \\\n  -p 18501:8501 -p 18080:8080 -p 16080:6080 computer-use-demo:verify\nuntil curl -sf localhost:18501\u002F_stcore\u002Fhealth >\u002Fdev\u002Fnull; do sleep 1; done\n```\n\nA cold build takes several minutes (apt, LibreOffice, a pyenv Python compile). The `requirements.txt` layer is cached separately, so source-only changes rebuild in seconds.\n\nTo iterate without rebuilding, copy sources over the baked copy before the first browser session compiles the script:\n\n```sh\ndocker cp computer_use_demo\u002F. cu-verify:\u002Fhome\u002Fcomputeruse\u002Fcomputer_use_demo\u002F\n```\n\nStreamlit's file watcher does not notice `docker cp` replacements once a session has run. Recreate the container instead of `docker restart`, which fails on a stale X lock (`tint2: could not open display`).\n\n## Drive the UI\n\nInstall Playwright in any venv (`pip install playwright && python -m playwright install chromium`) and run the script below. It sets the model, picks a tool version, optionally sets the thinking mode, sends a prompt, waits for the loop to go idle, then dumps the chat transcript and every HTTP exchange (request headers and JSON, response JSON) with auth headers redacted.\n\n```sh\nTHINKING=Adaptive python drive.py 18501 claude-sonnet-5 computer_toolset_20260801 \\\n  \"Take a screenshot, then zoom in on the taskbar and list the icons.\" out\u002F 240\n```\n\nPass `-` for model or tool version to keep the default. `THINKING=Off|Adaptive|Extended` clicks that radio. `TOKEN_EFFICIENT=1` ticks the beta checkbox.\n\nWhat to read afterwards:\n\n- `out\u002Fchat.txt`: the rendered conversation, including `Tool Use: \u003Cname>` lines and any error box with its traceback.\n- `out\u002Fexchange-NN.txt`: one file per API round trip. Check `tools`, `anthropic-beta`, and the `tool_use` \u002F `tool_result` blocks here rather than trusting the chat rendering.\n- `out\u002F02-chat.png`, `out\u002F04-http-logs-expanded.png`: full-page screenshots.\n\nUseful probes: an older model with a newer tool version (expect a clean 400 in the error box, not a crash), toggling Thinking to Off before the first message, and switching models mid-session.\n\n```python\n\"\"\"drive.py \u003Cport> \u003Cmodel|-> \u003Ctool_version|-> \u003Cprompt> \u003Coutdir> [wait_secs]\"\"\"\n\nimport os\nimport re\nimport sys\nimport time\nfrom pathlib import Path\n\nfrom playwright.sync_api import sync_playwright\n\nport, model, tool_version, prompt, outdir = sys.argv[1:6]\nwait_secs = int(sys.argv[6]) if len(sys.argv) > 6 else 180\nout = Path(outdir)\nout.mkdir(parents=True, exist_ok=True)\nMAIN = \"[data-testid='stMain'], section.main, [data-testid='stAppViewContainer']\"\n\n\ndef log(msg: str) -> None:\n    print(f\"[{time.strftime('%H:%M:%S')}] {msg}\", flush=True)\n\n\nwith sync_playwright() as p:\n    browser = p.chromium.launch()\n    page = browser.new_page(viewport={\"width\": 1400, \"height\": 1600})\n    page.goto(f\"http:\u002F\u002Flocalhost:{port}\", wait_until=\"networkidle\", timeout=120_000)\n    page.wait_for_selector(\"text=Tool Versions\", timeout=120_000)\n    sidebar = page.locator(\"[data-testid='stSidebar']\")\n\n    model_input = page.get_by_label(\"Model\", exact=True)\n    if model != \"-\":\n        model_input.fill(model)\n        model_input.press(\"Enter\")  # commits the text_input and fires on_change\n        time.sleep(2)\n    if tool_version != \"-\":\n        sidebar.get_by_text(tool_version, exact=True).click()\n        time.sleep(2)\n    if thinking := os.environ.get(\"THINKING\"):\n        sidebar.get_by_text(thinking, exact=True).click()\n        time.sleep(2)\n    if os.environ.get(\"TOKEN_EFFICIENT\"):\n        sidebar.get_by_text(\"Enable token-efficient tools beta\", exact=True).click()\n        time.sleep(2)\n    log(f\"model={model_input.input_value()!r} tools={tool_version} thinking={thinking}\")\n    page.screenshot(path=str(out \u002F \"01-sidebar.png\"), full_page=True)\n\n    chat = page.locator(\"textarea[data-testid='stChatInputTextArea']\")\n    chat.fill(prompt)\n    chat.press(\"Enter\")\n    log(\"prompt sent\")\n\n    # The status widget is present while the script (and so the sampling loop) runs.\n    deadline = time.time() + wait_secs\n    time.sleep(5)\n    while time.time() \u003C deadline:\n        running = page.locator(\"[data-testid='stStatusWidget']\").count() > 0\n        msgs = page.locator(\"[data-testid='stChatMessage']\").count()\n        log(f\"running={running} chat_messages={msgs}\")\n        if not running and msgs >= 2:\n            time.sleep(4)\n            if page.locator(\"[data-testid='stStatusWidget']\").count() == 0:\n                break\n        time.sleep(5)\n\n    page.screenshot(path=str(out \u002F \"02-chat.png\"), full_page=True)\n    (out \u002F \"chat.txt\").write_text(page.locator(MAIN).first.inner_text(timeout=10_000))\n\n    page.get_by_role(\"tab\", name=\"HTTP Exchange Logs\").click()\n    time.sleep(3)\n    expanders = page.locator(\"[data-testid='stExpander']\")\n    for i in range(expanders.count()):\n        exp = expanders.nth(i)\n        exp.locator(\"summary\").click()\n        time.sleep(1.5)\n        txt = exp.inner_text(timeout=15_000)\n        txt = re.sub(r\"(?im)^(`?)(authorization|x-api-key): .*$\", r\"\\1\\2: [REDACTED]\", txt)\n        (out \u002F f\"exchange-{i + 1:02d}.txt\").write_text(txt)\n    page.screenshot(path=str(out \u002F \"04-http-logs-expanded.png\"), full_page=True)\n    log(f\"captured {expanders.count()} exchanges\")\n    browser.close()\n```\n\n## Gotchas\n\n- The sidebar requires a non-empty API key for the Anthropic provider before it renders the chat. `ANTHROPIC_API_KEY` in the container env pre-fills it.\n- Each Playwright run is a fresh Streamlit session, so the HTTP exchange log only contains that run's requests. Capture it in the same run.\n- If `PYTEST_DISABLE_PLUGIN_AUTOLOAD` is set in your shell, `pytest` silently skips every async test. Run with `-p pytest_asyncio` or unset it.\n","# Verifying changes to this demo\n\nThe surface is the Streamlit app inside the container. Build the image from this directory, run it, and drive the UI with Playwright. `pytest`, `ruff`, and `pyright` are CI's job, not evidence.\n\n## Build and run\n\n```sh\ndocker build . -t computer-use-demo:verify\ndocker rm -f cu-verify 2>\u002Fdev\u002Fnull\ndocker run -d --name cu-verify \\\n  -e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY -e WIDTH=1024 -e HEIGHT=768 \\\n  -p 18501:8501 -p 18080:8080 -p 16080:6080 computer-use-demo:verify\nuntil curl -sf localhost:18501\u002F_stcore\u002Fhealth >\u002Fdev\u002Fnull; do sleep 1; done\n```\n\nA cold build takes several minutes (apt, LibreOffice, a pyenv Python compile). The `requirements.txt` layer is cached separately, so source-only changes rebuild in seconds.\n\nTo iterate without rebuilding, copy sources over the baked copy before the first browser session compiles the script:\n\n```sh\ndocker cp computer_use_demo\u002F. cu-verify:\u002Fhome\u002Fcomputeruse\u002Fcomputer_use_demo\u002F\n```\n\nStreamlit's file watcher does not notice `docker cp` replacements once a session has run. Recreate the container instead of `docker restart`, which fails on a stale X lock (`tint2: could not open display`).\n\n## Drive the UI\n\nInstall Playwright in any venv (`pip install playwright && python -m playwright install chromium`) and run the script below. It sets the model, picks a tool version, optionally sets the thinking mode, sends a prompt, waits for the loop to go idle, then dumps the chat transcript and every HTTP exchange (request headers and JSON, response JSON) with auth headers redacted.\n\n```sh\nTHINKING=Adaptive python drive.py 18501 claude-sonnet-5 computer_toolset_20260801 \\\n  \"Take a screenshot, then zoom in on the taskbar and list the icons.\" out\u002F 240\n```\n\nPass `-` for model or tool version to keep the default. `THINKING=Off|Adaptive|Extended` clicks that radio. `TOKEN_EFFICIENT=1` ticks the beta checkbox.\n\nWhat to read afterwards:\n\n- `out\u002Fchat.txt`: the rendered conversation, including `Tool Use: \u003Cname>` lines and any error box with its traceback.\n- `out\u002Fexchange-NN.txt`: one file per API round trip. Check `tools`, `anthropic-beta`, and the `tool_use` \u002F `tool_result` blocks here rather than trusting the chat rendering.\n- `out\u002F02-chat.png`, `out\u002F04-http-logs-expanded.png`: full-page screenshots.\n\nUseful probes: an older model with a newer tool version (expect a clean 400 in the error box, not a crash), toggling Thinking to Off before the first message, and switching models mid-session.\n\n```python\n\"\"\"drive.py \u003Cport> \u003Cmodel|-> \u003Ctool_version|-> \u003Cprompt> \u003Coutdir> [wait_secs]\"\"\"\n\nimport os\nimport re\nimport sys\nimport time\nfrom pathlib import Path\n\nfrom playwright.sync_api import sync_playwright\n\nport, model, tool_version, prompt, outdir = sys.argv[1:6]\nwait_secs = int(sys.argv[6]) if len(sys.argv) > 6 else 180\nout = Path(outdir)\nout.mkdir(parents=True, exist_ok=True)\nMAIN = \"[data-testid='stMain'], section.main, [data-testid='stAppViewContainer']\"\n\n\ndef log(msg: str) -> None:\n    print(f\"[{time.strftime('%H:%M:%S')}] {msg}\", flush=True)\n\n\nwith sync_playwright() as p:\n    browser = p.chromium.launch()\n    page = browser.new_page(viewport={\"width\": 1400, \"height\": 1600})\n    page.goto(f\"http:\u002F\u002Flocalhost:{port}\", wait_until=\"networkidle\", timeout=120_000)\n    page.wait_for_selector(\"text=Tool Versions\", timeout=120_000)\n    sidebar = page.locator(\"[data-testid='stSidebar']\")\n\n    model_input = page.get_by_label(\"Model\", exact=True)\n    if model != \"-\":\n        model_input.fill(model)\n        model_input.press(\"Enter\")  # commits the text_input and fires on_change\n        time.sleep(2)\n    if tool_version != \"-\":\n        sidebar.get_by_text(tool_version, exact=True).click()\n        time.sleep(2)\n    if thinking := os.environ.get(\"THINKING\"):\n        sidebar.get_by_text(thinking, exact=True).click()\n        time.sleep(2)\n    if os.environ.get(\"TOKEN_EFFICIENT\"):\n        sidebar.get_by_text(\"Enable token-efficient tools beta\", exact=True).click()\n        time.sleep(2)\n    log(f\"model={model_input.input_value()!r} tools={tool_version} thinking={thinking}\")\n    page.screenshot(path=str(out \u002F \"01-sidebar.png\"), full_page=True)\n\n    chat = page.locator(\"textarea[data-testid='stChatInputTextArea']\")\n    chat.fill(prompt)\n    chat.press(\"Enter\")\n    log(\"prompt sent\")\n\n    # The status widget is present while the script (and so the sampling loop) runs.\n    deadline = time.time() + wait_secs\n    time.sleep(5)\n    while time.time() \u003C deadline:\n        running = page.locator(\"[data-testid='stStatusWidget']\").count() > 0\n        msgs = page.locator(\"[data-testid='stChatMessage']\").count()\n        log(f\"running={running} chat_messages={msgs}\")\n        if not running and msgs >= 2:\n            time.sleep(4)\n            if page.locator(\"[data-testid='stStatusWidget']\").count() == 0:\n                break\n        time.sleep(5)\n\n    page.screenshot(path=str(out \u002F \"02-chat.png\"), full_page=True)\n    (out \u002F \"chat.txt\").write_text(page.locator(MAIN).first.inner_text(timeout=10_000))\n\n    page.get_by_role(\"tab\", name=\"HTTP Exchange Logs\").click()\n    time.sleep(3)\n    expanders = page.locator(\"[data-testid='stExpander']\")\n    for i in range(expanders.count()):\n        exp = expanders.nth(i)\n        exp.locator(\"summary\").click()\n        time.sleep(1.5)\n        txt = exp.inner_text(timeout=15_000)\n        txt = re.sub(r\"(?im)^(`?)(authorization|x-api-key): .*$\", r\"\\1\\2: [REDACTED]\", txt)\n        (out \u002F f\"exchange-{i + 1:02d}.txt\").write_text(txt)\n    page.screenshot(path=str(out \u002F \"04-http-logs-expanded.png\"), full_page=True)\n    log(f\"captured {expanders.count()} exchanges\")\n    browser.close()\n```\n\n## Gotchas\n\n- The sidebar requires a non-empty API key for the Anthropic provider before it renders the chat. `ANTHROPIC_API_KEY` in the container env pre-fills it.\n- Each Playwright run is a fresh Streamlit session, so the HTTP exchange log only contains that run's requests. Capture it in the same run.\n- If `PYTEST_DISABLE_PLUGIN_AUTOLOAD` is set in your shell, `pytest` silently skips every async test. Run with `-p pytest_asyncio` or unset it.\n",{"name":5,"description":7},"main","4a4224bdf0e9cfb3332167b69c90457403813625","computer-use-demo\u002F.claude\u002Fskills\u002Fverify",3491,"https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fclaude-quickstarts","https:\u002F\u002Fgithub.com\u002Fanthropics","https:\u002F\u002Fanthropic.com","2026-11-07 03:37:57",{"source":8,"skillName":5,"commands":45,"prompt":55,"zipAvailable":56},[46,49,52],{"tool":47,"command":48},"npx","npx skills add anthropics\u002Fclaude-quickstarts --skill verify",{"tool":50,"command":51},"bunx","bunx skills add anthropics\u002Fclaude-quickstarts --skill verify",{"tool":53,"command":54},"pnpm","pnpm dlx skills add anthropics\u002Fclaude-quickstarts --skill verify","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fclaude-quickstarts\u002Fblob\u002Fmain\u002Fcomputer-use-demo\u002F.claude\u002Fskills\u002Fverify\u002FSKILL.md",true,[],[59,70,79,96,104,116],{"skillNo":60,"name":61,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":62,"categories":63,"keywords":69,"publishedAt":31},"01M7189FFG0GVY39QBCTSYS5AZ","slack","https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fclaude-quickstarts\u002Fblob\u002Fmain\u002Fmanaged-agents\u002Fslack\u002Fskill.md",[64],{"categoryNo":65,"categoryName":66,"taxonomyType":67,"taxonomyTypeDesc":68},"01JBSEEDCAT000000000000005","邮件与沟通","SCENARIO","使用场景",[61],{"skillNo":71,"name":72,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":73,"categories":74,"keywords":78,"publishedAt":31},"01M7189D8D3CX3FPQEWYRH9D95","sentry","https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fclaude-quickstarts\u002Fblob\u002Fmain\u002Fmanaged-agents\u002Fsentry\u002Fskill.md",[75],{"categoryNo":76,"categoryName":77,"taxonomyType":67,"taxonomyTypeDesc":68},"01JBSEEDCAT000000000000023","Skill与智能体开发",[72],{"skillNo":80,"name":81,"nameZh":6,"description":82,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":85,"publishedAt":31},"01M7189B12649K1GD9TGXK7DBY","openshell-policy-advisor","Use when an OpenShell sandbox returns policy_denied, mentions policy.local, or needs a narrow network policy proposal.","https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fclaude-quickstarts\u002Fblob\u002Fmain\u002Fmanaged-agents\u002Fself-hosted-sandboxes\u002Fopenshell-policy\u002Fsandbox\u002Fopenshell-skills\u002Fpolicy-advisor\u002FSKILL.md",[],[86,87,88,89,90,91,23,92,93,94,95],"policy","advisor","openshell policy advisor","local","returns","when","proposal","denied","sandbox","network",{"skillNo":97,"name":98,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":99,"categories":100,"keywords":101,"publishedAt":31},"01M71899E0V3MWC8B65EWJ5P5W","roadtrip-planner","https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fclaude-quickstarts\u002Fblob\u002Fmain\u002Fmanaged-agents\u002Froadtrip-planner\u002Fskill.md",[],[102,103],"planner","roadtrip planner",{"skillNo":105,"name":106,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":107,"categories":108,"keywords":112,"publishedAt":31},"01M71895KCS8K44E1JFJTAX372","knowledge-wiki","https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fclaude-quickstarts\u002Fblob\u002Fmain\u002Fmanaged-agents\u002Fknowledge-wiki\u002Fskill.md",[109],{"categoryNo":110,"categoryName":111,"taxonomyType":67,"taxonomyTypeDesc":68},"01JBSEEDCAT000000000000021","资料检索与研究",[113,114,115],"wiki","knowledge","knowledge wiki",{"skillNo":117,"name":5,"nameZh":6,"description":118,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":119,"categories":120,"keywords":121,"publishedAt":31},"01M71893K7X8AS2JDBAMGG4HPX","Build and drive the copilot-kit-ag-ui demo to verify changes end-to-end.","https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fclaude-quickstarts\u002Fblob\u002Fmain\u002Fmanaged-agents\u002Fcopilot-kit-ag-ui\u002F.claude\u002Fskills\u002Fverify\u002FSKILL.md",[],[5,19,20,30,21,22,122,123,24,124,27,125],"copilot","kit","ui demo","ag"]