Build Script Verification

Verifying the build scripts

by anthropics · MIT license · ★ 8,221 on GitHub

Verifying the build scripts cover

Drive this repo's build/release scripts end-to-end without touching the network. Use when verifying changes to scripts/download_cli.py, scripts/build_wheel.py, scripts/update_cli_version.py, or scripts/_cli_version_validation.py.

---
name: verify
description: Drive this repo's build/release scripts end-to-end without touching the network. Use when verifying changes to scripts/download_cli.py, scripts/build_wheel.py, scripts/update_cli_version.py, or scripts/_cli_version_validation.py.
---

# Verifying the build scripts

The SDK itself is a library (drive it through `import claude_agent_sdk`), but
the `scripts/` directory is a set of **CLIs** run by the release workflows.
Verify them by running them, not by importing them.

## NEVER run the real installer

`scripts/download_cli.py` shells out to `curl https://claude.ai/install.sh | bash`
(and the PowerShell equivalent). Running it for real **overwrites the `claude`
binary on the developer's machine**. Do not run `bash install.sh`, and do not
invoke `download_cli.py` with `latest`/`stable` (or any case variant) against
the real network.

Overview

The SDK itself is a library (drive it through import claude_agent_sdk), but the scripts/ directory is a set of CLIs run by the release workflows. Verify them by running them, not by importing them.

Manual install (npx, ZIP)
Claude Codenpx skills add anthropics/claude-agent-sdk-python --skill verify -g -a claude-code
Claude Code (degit)npx degit anthropics/claude-agent-sdk-python/.claude/skills/verify#main ~/.claude/skills/verify
Claude.ai / desktopZip the folder and upload it under Settings → Capabilities → Skills.
Codex, Cursor, other agentsPoint them at SKILL.md. The other files are plain text.

Connects with Agent Alley MCP · agentalley.io/mcp

Files included

  • SKILL.md3.6 KB
Read SKILL.md here
anthropics/main1 file shown
SKILL.md
Show the full text80 lines

Verifying the build scripts

The SDK itself is a library (drive it through import claude_agent_sdk), but the scripts/ directory is a set of CLIs run by the release workflows. Verify them by running them, not by importing them.

NEVER run the real installer

scripts/download_cli.py shells out to curl https://claude.ai/install.sh | bash (and the PowerShell equivalent). Running it for real overwrites the claude binary on the developer's machine. Do not run bash install.sh, and do not invoke download_cli.py with latest/stable (or any case variant) against the real network.

Instead, put stub curl / bash / powershell on a temp PATH and drive the script under env -i with an isolated HOME (so find_installed_cli() cannot discover the real binary and copy it into src/claude_agent_sdk/_bundled/).

The harness

SB=$(mktemp -d); mkdir -p $SB/stub $SB/home $SB/repo/src/claude_agent_sdk
cp scripts/{download_cli.py,build_wheel.py,update_cli_version.py,_cli_version_validation.py} $SB/repo/scripts/
printf '__cli_version__ = "2.1.208"\n' > $SB/repo/src/claude_agent_sdk/_cli_version.py

cat > $SB/stub/curl <<'EOF'
#!/bin/bash
out=""; prev=""; for a in "$@"; do [ "$prev" = "-o" ] && out="$a"; prev="$a"; done
echo "[stub curl] argv: $*" >> "$MARKER"
[ -n "$out" ] && printf '%b' "${CURL_BODY:-#!/bin/bash\necho hi\n}" > "$out"
exit ${CURL_EXIT:-0}
EOF
cat > $SB/stub/bash <<'EOF'
#!/bin/bash
{ echo "[stub bash] argc=$#"; for a in "$@"; do echo "    <$a>"; done; } >> "$MARKER"
EOF
chmod +x $SB/stub/*

cd $SB/repo
env -i HOME=$SB/home PATH=$SB/stub:/usr/bin:/bin MARKER=$SB/m \
    CLAUDE_CLI_VERSION=2.1.208 .venv/bin/python scripts/download_cli.py

run_command() captures the child's output, so the stubs must log to a $MARKER file — printing to stderr is swallowed.

Flows worth driving

  • update_cli_version.py <version> — the whole validator surface is reachable here: a concrete version writes the file; latest/stable, v2.1.207, next, 2.1, and a quote-breakout string each exit 1 with a distinct message and leave the file untouched.
  • build_wheel.py --skip-sdist — reads the pin, then chains into download_cli.py. Rewrite _cli_version.py in the sandbox to a moving tag / single quotes / garbage / delete it: each must fail before any subprocess is spawned. --cli-version <v> bypasses the pin (intentional escape hatch; the release workflow does not use it).
  • download_cli.py — set CURL_BODY to an HTML error page or an empty string to prove the body check refuses it with no retry; empty the PATH to prove a missing curl fails fast in one attempt; CURL_EXIT=22 to prove a genuine transient failure still retries 3×.
  • The Windows path is unreachable on Linux. It is behind platform.system() == "Windows". Drive it with a small runner that patch.object(m.platform, "system", return_value="Windows") and a stub powershell that reads the -Command text and honours $env:CLAUDE_CLI_INSTALL_SCRIPT. This is the one place where forcing the platform is legitimate.

Gotchas

  • ${CURL_BODY:-default} treats an empty body as unset. Use a separate stub that does : > "$out" to test the empty-body branch.
  • The retry path really sleeps (jitter up to 5s, then 2s + 4s). A full three-attempt run takes ~10s; budget for it rather than assuming a hang.
1---
2name: verify
3description: Drive this repo's build/release scripts end-to-end without touching the network. Use when verifying changes to scripts/download_cli.py, scripts/build_wheel.py, scripts/update_cli_version.py, or scripts/_cli_version_validation.py.
4---
5 
6# Verifying the build scripts
7 
8The SDK itself is a library (drive it through `import claude_agent_sdk`), but
9the `scripts/` directory is a set of **CLIs** run by the release workflows.
10Verify them by running them, not by importing them.
11 
12## NEVER run the real installer
13 
14`scripts/download_cli.py` shells out to `curl https://claude.ai/install.sh | bash`
15(and the PowerShell equivalent). Running it for real **overwrites the `claude`
16binary on the developer's machine**. Do not run `bash install.sh`, and do not
17invoke `download_cli.py` with `latest`/`stable` (or any case variant) against
18the real network.
19 
20Instead, put stub `curl` / `bash` / `powershell` on a temp `PATH` and drive the
21script under `env -i` with an isolated `HOME` (so `find_installed_cli()` cannot
22discover the real binary and copy it into `src/claude_agent_sdk/_bundled/`).
23 
24## The harness
25 
26```bash
27SB=$(mktemp -d); mkdir -p $SB/stub $SB/home $SB/repo/src/claude_agent_sdk
28cp scripts/{download_cli.py,build_wheel.py,update_cli_version.py,_cli_version_validation.py} $SB/repo/scripts/
29printf '__cli_version__ = "2.1.208"\n' > $SB/repo/src/claude_agent_sdk/_cli_version.py
30 
31cat > $SB/stub/curl <<'EOF'
32#!/bin/bash
33out=""; prev=""; for a in "$@"; do [ "$prev" = "-o" ] && out="$a"; prev="$a"; done
34echo "[stub curl] argv: $*" >> "$MARKER"
35[ -n "$out" ] && printf '%b' "${CURL_BODY:-#!/bin/bash\necho hi\n}" > "$out"
36exit ${CURL_EXIT:-0}
37EOF
38cat > $SB/stub/bash <<'EOF'
39#!/bin/bash
40{ echo "[stub bash] argc=$#"; for a in "$@"; do echo " <$a>"; done; } >> "$MARKER"
41EOF
42chmod +x $SB/stub/*
43 
44cd $SB/repo
45env -i HOME=$SB/home PATH=$SB/stub:/usr/bin:/bin MARKER=$SB/m \
46 CLAUDE_CLI_VERSION=2.1.208 .venv/bin/python scripts/download_cli.py
47```
48 
49`run_command()` captures the child's output, so the stubs must log to a
50`$MARKER` file — printing to stderr is swallowed.
51 
52## Flows worth driving
53 
54- **`update_cli_version.py <version>`** — the whole validator surface is
55 reachable here: a concrete version writes the file; `latest`/`stable`,
56 `v2.1.207`, `next`, `2.1`, and a quote-breakout string each exit 1 with a
57 distinct message and leave the file untouched.
58- **`build_wheel.py --skip-sdist`** — reads the pin, then chains into
59 `download_cli.py`. Rewrite `_cli_version.py` in the sandbox to a moving tag /
60 single quotes / garbage / delete it: each must fail *before* any subprocess
61 is spawned. `--cli-version <v>` bypasses the pin (intentional escape hatch;
62 the release workflow does not use it).
63- **`download_cli.py`** — set `CURL_BODY` to an HTML error page or an empty
64 string to prove the body check refuses it with no retry; empty the `PATH` to
65 prove a missing `curl` fails fast in one attempt; `CURL_EXIT=22` to prove a
66 genuine transient failure still retries 3×.
67- **The Windows path is unreachable on Linux.** It is behind
68 `platform.system() == "Windows"`. Drive it with a small runner that
69 `patch.object(m.platform, "system", return_value="Windows")` and a stub
70 `powershell` that reads the `-Command` text and honours
71 `$env:CLAUDE_CLI_INSTALL_SCRIPT`. This is the one place where forcing the
72 platform is legitimate.
73 
74## Gotchas
75 
76- `${CURL_BODY:-default}` treats an *empty* body as unset. Use a separate stub
77 that does `: > "$out"` to test the empty-body branch.
78- The retry path really sleeps (jitter up to 5s, then 2s + 4s). A full
79 three-attempt run takes ~10s; budget for it rather than assuming a hang.
80 
View all files on GitHub →

Details

License
MIT
Stars on the repo
★ 8,221
Checked
Source
anthropics/claude-agent-sdk-python ↗
Creator
anthropics · 35 listings
View creator

Similar skills

See all →

More from anthropics

SkillAcademy Guideanthropics/skills · by anthropicsStop and check this skill before finishing any reply to a question about how to use Claude or a Claude product — it recommends matching courses, tutorials, and use cases from Claude Academy (academy.claude.com), Anthropic's learning hub. Trigger on: "how do I", "how can I", "getting started with", "what can Claude do", "teach me", "learn to use"; questions about artifacts, projects, skills, plugins, connectors, MCP; requests about rolling Claude out to a team, class, or organization; and any ask for training materials, onboarding content, or learning resources. Use it when the user is learning how to use a feature or product — not when they are mid-task and just want the task done. This skill composes with other skills: after consulting product documentation to answer how a Claude feature works, also check here for a matching course or tutorial — a docs-grounded answer and an Academy recommendation belong together. Only recommend on a strong match; never invent Academy content.★ 178k GitHub starsSkillGenerative Art Creatoranthropics/skills · by anthropicsCreating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.★ 178k GitHub starsSkillAnthropic Style Guideanthropics/skills · by anthropicsApplies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.★ 178k GitHub starsSkillDiscord Channel Setupanthropics/claude-plugins-official · by anthropicsSet up the Discord channel — save the bot token and review access policy. Use when the user pastes a Discord bot token, asks to configure Discord, asks "how do I set this up" or "who can reach me," or wants to check channel status.★ 37.6k GitHub starsSkillM5Stack Setup Guideanthropics/claude-plugins-official · by anthropicsEnd-to-end onboarding for a freshly-plugged-in M5Stack ESP32 device (Cardputer, Cardputer-Adv, Core, CoreS3, Stick) — detect on USB, flash UIFlow 2.0 firmware, and install the Claude Buddy MicroPython app bundle. Use whenever the user plugs in or wants to flash/provision/reset an M5Stack or ESP32 board, or says "m5-onboard go".★ 37.6k GitHub starsSkillVisual Art Generatoranthropics/skills · by anthropicsCreate beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.★ 178k GitHub stars