Skip to content

Instantly share code, notes, and snippets.

@donbr
Created July 7, 2026 23:06
Show Gist options
  • Select an option

  • Save donbr/1ef9974730b7687eab1df4a3b8abcc6f to your computer and use it in GitHub Desktop.

Select an option

Save donbr/1ef9974730b7687eab1df4a3b8abcc6f to your computer and use it in GitHub Desktop.
Claude Code Best Practices

Session 11 — Claude Code & the Claude Agent SDK: Learning Journey (Student Version)

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, with ANTHROPIC_API_KEY in a git-ignored .env when you reach Guide 3.

Legend: ✅ verified against official docs / the installed SDK · ⚠️ watch this — a subtle or easy-to-miss point · 💡 optional, do-it-better tip


The short version: are the guides trustworthy?

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."


Guide-by-guide notes

README.md — the session hub ✅

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.

01_Installing_Claude_Code.md ✅ clean

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. If node --version is 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 c to copy the URL). The guide calls this out — don't fight the browser callback.

02_Using_Claude_Code.md ✅ · ⚠️ one thing to get right

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:

  • auto and dontAsk are genuine modes. auto auto-approves tool calls with background safety checks (it's currently a research preview); dontAsk auto-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's settings.local.json overrides the shared settings.json, which overrides your personal user file (and managed settings + --flags beat everything). Same idea as CLAUDE.md layering.
  • 💡 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.

03_Claude_Agent_SDK.md ✅ API-accurate · 💡 two upgrades

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 old claude-code-sdk is deprecated. Proof: the installed package has no ClaudeCodeOptions symbol — only ClaudeAgentOptions. If a tutorial imports claude_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 as mcp__<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_id path. The guide grabs the id from the init SystemMessage via message.data["session_id"] (correct). But ResultMessage also 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 ResultMessage path 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.


What to actually watch for (the five real trip-wires)

  1. Node 22+ for the npm CLI install — or just use the native installer (no Node).
  2. Settings precedence: narrower/local layer wins; managed + CLI flags beat all.
  3. ClaudeAgentOptions, not ClaudeCodeOptions — and claude-agent-sdk, not claude-code-sdk. Old imports are the #1 stale-tutorial tell.
  4. session_id comes from the init SystemMessage.data or ResultMessage.session_id — pick deliberately; a fresh query() with no resume has no memory of the last turn.
  5. 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.

Questions & Activities — reason it through yourself (no answers here)

These are the graded deliverables. Answer #1–#4 in README.md and 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 + Write let 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.md loads 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 do max_turns and permission_mode each bound? That's your answer to "how the allowlist replaces the human gate."

Activity #1 & the Advanced Activity — where to look

  • 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 as mcp__concierge__<name>. Pick one genuinely useful for your repo.
  • Advanced (cat shop): your Session 8 server plugs into the same mcp_servers option 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?

References

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).

Claude Code (Guides 1–2)

Claude Agent SDK (Guide 3)

Tools move fast. If a command or field ever disagrees with these docs, the docs win — re-verify against the URLs above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment