PROJECT · 3 hours
Building with the SDK
Use the Anthropic SDK and Claude Code Agent SDK to automate real tasks in your development workflow
Why the SDK
When I first started automating parts of my SDLC harness, the Claude.ai chat interface hit a wall quickly. I needed to trigger AI analysis from a script, pass structured inputs, and route the output back into a pipeline — none of which are things you can do interactively. That's when the SDK became essential.
There are two SDKs to understand, and picking the wrong one is a common early mistake.
The Anthropic SDK (@anthropic-ai/sdk) talks directly to the Claude API. You construct a message, send it, and get a response. No file system access, no tools — just a conversation. This is the right choice when you're calling Claude from your own application code: summarizing a diff, classifying a ticket, generating a commit message.
The Claude Code Agent SDK (@anthropic-ai/claude-agent-sdk) runs Claude Code as a subprocess. The agent can use real tools — Read, Edit, Bash, Glob — and iterate until a task is done. This is what powers my SDLC harness when I need Claude to actually do something in the repo, not just say something about it.
Think of it this way: the Anthropic SDK is a skilled consultant you call on the phone. The Agent SDK is that same consultant sitting at your desk with access to your codebase. Different situations call for different modes.
Which to use? If you need a text response to a text question, use @anthropic-ai/sdk. If you need Claude to read, edit, or execute files, use @anthropic-ai/claude-agent-sdk. Most real workflows use both.
When Each Matters
In my orchestration system, I use the Anthropic SDK for decision-making steps — "should this task block on review?" — and the Agent SDK for execution steps — "actually run the review and edit the report." Separating these two concerns keeps the architecture clean and testable.
The Agent SDK has one entry point: the query() async iterable. You iterate its output stream, and each message tells you what the agent is doing. The Anthropic SDK uses the familiar messages.create() pattern you may already know.
Install both: npm install @anthropic-ai/sdk @anthropic-ai/claude-agent-sdk
First SDK Call
The simplest possible Anthropic SDK call looks like this. I use this pattern whenever I need Claude's reasoning embedded in a larger script — no class, no framework, just a function call.
Simplest Direct API Call
Notice: new Anthropic() (not new Client()), and the response comes back in response.content[0]. The model id claude-haiku-4-5 is fast and cheap — good for high-frequency automation tasks.
For agentic tasks that need real file access, switch to the Agent SDK:
Agent SDK — File-Aware Task
Don't mix them up. Using the Anthropic SDK where you need file access means you'll have to read and inject file contents yourself — messy and error-prone at scale. Use the Agent SDK when the task is inherently agentic.
Staged Build
Here's how I actually use these SDKs in my SDLC harness. The harness needs to review code changes after each task completes. I'll walk through building this reviewer in three stages so you can see how the pattern grows.
Stage 1 — The core function. Start with the minimum: take a diff string, return a review.
Stage 1: Core Review Function
Stage 2 — Add git integration. The review is more useful if it knows what files changed and what branch context exists.
Stage 2: Pull Diff from Git
Stage 3 — Integrate with the SDLC pipeline. In my harness, the reviewer runs as a step in the task pipeline. The result is written to a report file so the orchestrator can read it.
Stage 3: Pipeline Integration
This is the actual pattern I use. No invented utility classes, no complex frameworks — just composable functions calling the API and writing output to files the orchestrator can consume.
Reflective prompt: At Stage 3, I'm asking Claude to classify its own review output. What failure mode does that introduce, and how would you guard against it?
Composition over classes. Keeping SDK calls in plain functions makes them easy to test in isolation. You can mock client.messages.create() in tests without needing a full class hierarchy to substitute.
Checkpoint
Before moving to the quiz, check your understanding:
- If a task needs to read three files and edit one, which SDK do you reach for and why?
- My
runCodeReviewStepfunction calls Claude twice. What are the two calls for, and could you combine them into one? - What does
allowedTools: ['Read', 'Glob', 'Bash']actually control in the Agent SDK?
These aren't rhetorical — sketch your answers before moving on. The quiz tests the same concepts.
Pattern to remember: Anthropic SDK = your code calls Claude to get a decision. Agent SDK = Claude runs with tools to complete a task. The two compose naturally in a pipeline.
Knowledge Check
1. You need to summarize the content of a file and return it as a string in your Node.js script. Which SDK is the right choice?
- A)@anthropic-ai/claude-agent-sdk — because it can read files
- B)@anthropic-ai/sdk — you read the file yourself and pass the content in the prompt
- C)Either works equally well for this task
- D)Neither — you should use the Claude.ai chat interface
Show Answer
Correct Answer: B
For a simple read-and-summarize task, the Anthropic SDK is the right choice. You read the file with Node's fs module, inject the content into the prompt, and get back a text response. The Agent SDK is for tasks where you need Claude to autonomously use tools — overkill here.
2. In the Agent SDK, what does iterating the `query()` async iterable give you?
- A)A single final response object when the agent finishes
- B)A stream of messages including tool calls, tool results, and the final result
- C)Only the final text result — intermediate steps are hidden
- D)One message per file the agent reads
Show Answer
Correct Answer: B
The Agent SDK is a streaming async iterable. Each iteration can be a tool call, a tool result, an intermediate reasoning step, or the final result. You check for 'result' in message to detect the final output.
3. You call `new Anthropic()` but forget to set ANTHROPIC_API_KEY in your environment. What happens?
- A)The client initializes fine; the error appears only on the first API call
- B)The constructor throws immediately with an auth error
- C)The client uses a guest mode with rate limits
- D)The call succeeds but returns empty responses
Show Answer
Correct Answer: A
The Anthropic client constructor does not validate the key — it just reads the environment variable. The error surfaces on the first actual API call when the server rejects the missing or invalid key.
4. In Stage 2 of the staged build, `git diff main...HEAD` uses three dots. What does the three-dot syntax do differently from two dots?
- A)Three dots compares the full history; two dots only the last commit
- B)Three dots diffs from where the branch diverged from main; two dots diffs all commits on both branches
- C)They are equivalent in modern git
- D)Three dots includes untracked files; two dots does not
Show Answer
Correct Answer: B
Three dots (`main...HEAD`) shows changes introduced by the current branch since it diverged from main — equivalent to the 'this branch only' view. Two dots (`main..HEAD`) can include commits reachable from HEAD but not main, which behaves differently in history-heavy repos.
5. The `reviewDiff` function passes a `system` prompt. What purpose does the system prompt serve here that putting the same text in the user message would not?
- A)System prompts are required by the API; user messages alone are rejected
- B)System prompts are cached between calls, reducing cost for repeated invocations
- C)System prompts set persistent instructions that frame every user message in the conversation
- D)There is no functional difference — it is a style preference only
Show Answer
Correct Answer: C
The system prompt establishes persistent instructions (role, style, constraints) that apply to every turn. Putting the same text in the user message works for single-turn calls, but as you add multi-turn context or retries, the system prompt keeps the framing stable without repeating it in every user message.
6. Why does `runCodeReviewStep` write the review to a file rather than returning it directly to the caller?
- A)File I/O is faster than returning large strings in Node.js
- B)The orchestrator reads reports from files, so writing to a file is the integration contract
- C)Claude's output cannot be returned as a string — it must be written to disk
- D)This is a security best practice to avoid passing sensitive code through function returns
Show Answer
Correct Answer: B
In a pipeline where multiple agents and steps coordinate, a shared file system is often the simplest integration contract. The orchestrator knows to look for `reports/{taskName}-review.md` — no direct function call coupling required. This is the same pattern used in my SDLC harness.
7. You want to test `reviewDiff` in Jest without making real API calls. What is the cleanest approach?
- A)Set ANTHROPIC_API_KEY to a test key that returns dummy responses
- B)Mock `client.messages.create` to return a fixed response object
- C)Wrap the function call in a try/catch and assert the catch block
- D)Testing functions that call external APIs is not practical — skip the test
Show Answer
Correct Answer: B
The cleanest approach is to mock `client.messages.create` (or the whole `@anthropic-ai/sdk` module) to return a predictable response object. This lets you test the function's behavior — parsing the response, handling empty diffs, writing the file — without a live API key or network call.