A companion to the four session guides (README.md, 01_Installing_Claude_Code.md,
02_Using_Claude_Code.md, 03_Claude_Agent_SDK.md). It's a validation log: every
command and API call in those guides was checked against the official Claude Code /
Claude Agent SDK docs (and against the real installed SDK), so you don't lose time on a
stale flag or a wrong field name. Use it as a "known-good" reference while you install,
drive Claude Code, and wire up the agent. All the doc links you'll want are collected in
References.
This is the student version. The engineering findings and gotchas are kept, but the answers to the graded Questions #1–#4 are intentionally removed — those are yours to reason out and write in
README.md. Prompts to get you there are near the end. No API keys appear here; anything key-shaped is a<placeholder>.
A reference environment (yours may differ): WSL2 (Ubuntu 22.04), Claude Code 2.x, Python 3.10+ via
uv, Node 20.x, withANTHROPIC_API_KEYin a git-ignored.envwhen you reach Guide 3.
Legend: ✅ verified against official docs / the installed SDK ·
Yes. Across all four documents there were no broken commands and no wrong APIs — every install path, CLI flag, slash command, permission mode, and SDK call checks out. There is exactly one clarification worth internalizing (settings precedence in Guide 2) and a couple of optional "do it the cleaner way" tips. The notes below are less "errata" and more "the handful of subtle spots where people trip."
The build arc (Breakout 1 = FastAPI + echo stub skeleton; Breakout 2 = swap the stub for
a real agent via query()), the four questions, the activities, and the submission steps
all line up with the three guides. One cosmetic thing: the Agent SDK resource links point
at docs.anthropic.com/en/api/agent-sdk/..., which redirects to the canonical
code.claude.com/docs/en/agent-sdk/.... Both work; the References section uses the
canonical form.
Every install path is current — native installer, Homebrew casks (claude-code and
claude-code@latest), WinGet (Anthropic.ClaudeCode), and npm
(@anthropic-ai/claude-code). Auth options (subscription / Console / Bedrock·Vertex·
Microsoft Foundry) are correct. claude --version, claude doctor, claude update,
and the settings.json auto-update keys all check out.
⚠️ The npm route needs Node 22+ — stricter than people expect. Ifnode --versionis below 22, the npm install fails. This is exactly why the guide recommends the native installer: it bundles its own runtime and needs no Node at all. Prefer it.- 💡 On WSL2/SSH/containers where the browser can't hand the login token back, use the
paste-a-code flow (press
cto copy the URL). The guide calls this out — don't fight the browser callback.
Flags (-p/-c/-r/--model/--permission-mode/--add-dir/--output-format), the
slash-command table, the CLAUDE.md hierarchy, and the extensibility surface (custom
commands, skills, subagents, hooks, MCP) are all accurate. The permission modes are real —
including the two "specialized" ones the guide mentions:
- ✅
autoanddontAskare genuine modes.autoauto-approves tool calls with background safety checks (it's currently a research preview);dontAskauto-denies anything not pre-approved via/permissions. You won't need either for the assignment, but they're not made up. ⚠️ Settings precedence — know which layer wins. The guide lists the layers~/.claude/settings.json→.claude/settings.json→.claude/settings.local.json. Read that as increasing precedence: the narrower/later file wins. Full order, highest → lowest: enterprise-managed → CLI flags →.claude/settings.local.json→.claude/settings.json→~/.claude/settings.json. So a project'ssettings.local.jsonoverrides the sharedsettings.json, which overrides your personal user file (and managed settings +--flagsbeat everything). Same idea asCLAUDE.mdlayering.- 💡 The plan → implement → verify loop is the whole point of Task 3. Actually read the plan Claude proposes and push back before approving — that's the cheap moment to steer.
This guide was checked symbol-by-symbol against the installed claude-agent-sdk — not
just the docs — so the code you'll type is verified against the real package. Findings:
-
✅ The rename is real. The current package is
claude-agent-sdk(Python) /@anthropic-ai/claude-agent-sdk(npm); the oldclaude-code-sdkis deprecated. Proof: the installed package has noClaudeCodeOptionssymbol — onlyClaudeAgentOptions. If a tutorial importsclaude_code_sdk, it's stale. -
✅ Every option field and signature matches:
query(prompt=..., options=...)as an async iterator;ClaudeAgentOptions(allowed_tools, cwd, system_prompt, max_turns, resume, mcp_servers, permission_mode, can_use_tool, hooks);@tool(name, description, schema);create_sdk_mcp_server(name, version, tools); tool-name allowlisting asmcp__<server>__<tool>. All confirmed. -
✅ Version floors: the SDK needs Python 3.10+ (note: lower than the Claude Code npm CLI's Node 22+ — different package, don't conflate them). TS SDK needs Node 18+.
-
💡 Task 7 — there's a cleaner
session_idpath. The guide grabs the id from the initSystemMessageviamessage.data["session_id"](correct). ButResultMessagealso carries it directly:from claude_agent_sdk import ResultMessage async for message in query(prompt=..., options=opts): ... if isinstance(message, ResultMessage): session_id = message.session_id # direct attribute, no .data lookup
Use whichever fits — the init path gives you the id early; the
ResultMessagepath is guaranteed at the end. Knowing both saves a debugging session. -
💡 The built-in tools list is illustrative. Read/Write/Edit/Bash/Glob/Grep/WebSearch are all real, and there are more (WebFetch, etc.). For the concierge you only allowlist the read-only three — that restriction is your server-side safety story.
- Node 22+ for the npm CLI install — or just use the native installer (no Node).
- Settings precedence: narrower/local layer wins; managed + CLI flags beat all.
ClaudeAgentOptions, notClaudeCodeOptions— andclaude-agent-sdk, notclaude-code-sdk. Old imports are the #1 stale-tutorial tell.session_idcomes from the initSystemMessage.dataorResultMessage.session_id— pick deliberately; a freshquery()with noresumehas no memory of the last turn.- Custom tools must be allowlisted by their full name
mcp__<server>__<tool>, exactly like built-ins — forget it and the model simply can't call your tool.
These are the graded deliverables. Answer #1–#4 in
README.mdand demo the activities in your Loom. The prompts below are a method, not the answer.
Question #1 — Why does a shell-capable agent need a permission system, and why is plan mode so valuable from an empty directory?
Ask yourself:
- List what
Bash+Edit+Writelet an agent do that a chat window can't. Which of those are irreversible? Who normally decides they're OK — and on a server, who's missing? - In plan mode the agent literally can't execute. Why is "read a proposed plan and push back" cheaper than "undo files it already wrote"? When is a project most ambiguous — and is that before or after the first file exists?
Question #2 — What belongs in CLAUDE.md (and what doesn't)? How does that connect to Session 3's context/memory?
Ask yourself:
CLAUDE.mdloads into every session. What is each line costing you, every time?- Sort your candidate lines into "the model could learn this by reading the code" vs.
"it couldn't." Which pile belongs in
CLAUDE.md? - In Session 3 you managed a growing conversation (summarize/trim). Here the budget is a fixed always-on prefix. Same scarcity — so what discipline carries over?
Question #3 — Vs. your hand-built LangGraph agents: what does the SDK give you free, and what do you give up?
Ask yourself:
- In Sessions 2–4 you wrote the loop, the tool dispatch, the retries, the state. Which of those does the SDK now own? What did that plumbing cost you in bugs/time?
- What can a custom LangGraph topology express that "one opinionated agent loop" can't? What about model-provider choice?
- Frame it as library-vs-framework: when would you want the SDK's opinions, and when would you reach back for LangGraph?
Question #4 — Why route every message through query() instead of a raw chat-completion — and what new risk do tools add? How did your allowlist + permission mode handle it?
Ask yourself:
- A plain chat completion returns text. To answer "what does this repo do?" it would need…
what, that
query()gives you for free? - Now the risk: an agent with tools can act. On a server, who's clicking "approve"? What does a user typing "delete everything" become — and what's the injection surface?
- Trace your config: with
allowed_tools=["Read","Glob","Grep"], can any message make the agent write or run a shell command? Why not? What domax_turnsandpermission_modeeach bound? That's your answer to "how the allowlist replaces the human gate."
- Live streaming (option 1): it's in the Task 5 message stream. Which message type carries tool-use blocks you could push to the browser over SSE? Which one means "done"?
- Multi-conversation (option 2): it's Task 7 generalized. What data structure maps each browser conversation to its own SDK session so they don't cross-talk?
- Second tool (option 3): reuse the Task 8 pattern — another
@tool, allowlisted asmcp__concierge__<name>. Pick one genuinely useful for your repo. - Advanced (cat shop): your Session 8 server plugs into the same
mcp_serversoption as an external HTTP entry. What key shape does an external HTTP MCP server take, and how do you allowlist its tools? What handles the OAuth you wrote in Session 8?
Official, first-party docs — the "known-good" source when anything disagrees. Claude Code
docs home: https://code.claude.com/docs. The Agent SDK lives under
code.claude.com/docs/en/agent-sdk/* (old docs.anthropic.com/en/api/agent-sdk/* links
redirect here).
- Quickstart — https://code.claude.com/docs/en/quickstart
- Set up Claude Code (install, Node 22+ for npm, system reqs) — https://code.claude.com/docs/en/setup
- Authentication (subscription / Console / Bedrock·Vertex·Microsoft Foundry;
/login·/logout) — https://code.claude.com/docs/en/authentication - CLI reference (flags) — https://code.claude.com/docs/en/cli-reference
- Slash commands — https://code.claude.com/docs/en/slash-commands
- Permissions & permission modes (
plan/acceptEdits/bypassPermissions/auto/dontAsk; precedence) — https://code.claude.com/docs/en/permissions - Settings (layering,
autoUpdatesChannel,DISABLE_AUTOUPDATER) — https://code.claude.com/docs/en/settings - Memory /
CLAUDE.md— https://code.claude.com/docs/en/memory - Skills — https://code.claude.com/docs/en/skills
- Subagents — https://code.claude.com/docs/en/sub-agents
- Hooks — https://code.claude.com/docs/en/hooks
- MCP (
claude mcp add,.mcp.json) — https://code.claude.com/docs/en/mcp - Model configuration — https://code.claude.com/docs/en/model-config
- Claude Code Best Practices — https://www.anthropic.com/engineering/claude-code-best-practices
- Overview & quickstart (Python 3.10+) — https://code.claude.com/docs/en/agent-sdk/overview
- Python SDK reference (
query,ClaudeAgentOptions, message types) — https://code.claude.com/docs/en/agent-sdk/python - TypeScript SDK reference (Node 18+) — https://code.claude.com/docs/en/agent-sdk/typescript
- Custom tools & in-process MCP (
@tool,create_sdk_mcp_server,mcp__server__tool) — https://code.claude.com/docs/en/agent-sdk/custom-tools - Sessions (
resume,session_id) — https://code.claude.com/docs/en/agent-sdk/sessions - MCP in the SDK (external stdio/HTTP/SSE) — https://code.claude.com/docs/en/agent-sdk/mcp
- Permissions in the SDK (
can_use_tool) — https://code.claude.com/docs/en/agent-sdk/permissions - Migration guide (
claude-code-sdk→claude-agent-sdk) — https://code.claude.com/docs/en/agent-sdk/migration-guide - Building Agents with the Claude Agent SDK — https://www.anthropic.com/engineering/building-agents-with-the-claude-agent-sdk
Tools move fast. If a command or field ever disagrees with these docs, the docs win — re-verify against the URLs above.