Claude Platform 101
From a first API call to tool use, skills, context management and managed agents.
Series Claude Academy: Start your journey Part 5 of 5
A walkthrough of the Claude Academy course Claude Platform 101 (Start your journey track, 13 lessons + quiz). Each lesson is summarised with my own tables and examples; take the course for the full lessons. All the courses are listed in the Claude Academy course index.
Note: Detailed content expanded from course outline and public lesson pages; verify against lessons. Model IDs, tool versions, and beta headers below are as shown in the lessons at time of writing and change often — check the API docs before use.
Prerequisites: Comfortable reading/writing code in at least one language; basic CLI. Most demos use the Python SDK (pip install anthropic); “Your first API call”, “What is tool use?”, and “Building with Claude Code” use the TypeScript SDK (@anthropic-ai/sdk). Need a Claude Console account + API key from platform.claude.com (small free credit, then Settings > Billing). No prior LLM-building experience needed.
Audience: Developers who’ve used Claude in chat and want to build it into their own applications — from a single request to a production agent.
Module 1 — Foundations
What is the Claude Platform?
- Anthropic’s infrastructure for building with Claude programmatically: REST API, SDKs, CLIs, and the Claude Console (API keys, usage, managed agents, prompt testing).
- Three layers — “build with primitives, scale on infrastructure, run with control”:
| Layer | Contents |
|---|---|
| Primitives | Messages API, tool use, files, web search, code execution, MCP servers, skills |
| Infrastructure | Managed agents, retries, queues, observability |
| Controls | Dashboards, evals |
- Example: a help-desk “draft reply” button = one
messages.createcall with a tone/guidelines system prompt.client = anthropic.Anthropic() response = client.messages.create( model="claude-haiku-4-5", # simple task -> fast, cheap model max_tokens=1024, system=TONE_AND_GUIDELINES, messages=[{"role": "user", "content": ticket_content}], )
Your first API call
- Keep the API key in
.env.local(never hard-code / commit).npm install @anthropic-ai/sdk. - Every request: model, max_tokens, messages (user/assistant roles); optional system prompt shapes persona.
import Anthropic from "@anthropic-ai/sdk"; const client = new Anthropic(); const response = await client.messages.create({ model: "claude-sonnet-5", max_tokens: 2048, system: "You are a terse senior code reviewer. Give feedback in one paragraph.", messages: [{ role: "user", content: `Review this code:\n${buggyCode}` }], }); for (const block of response.content) { if (block.type === "text") console.log(block.text); } response.contentis an array of blocks (text, tool_use, thinking…) — always loop and checktype.- In a product, the same call sits inside a route handler (e.g., a “summarize transcript” endpoint).
Choosing the right model
| Tier | Positioning (per lesson) | Use for |
|---|---|---|
| Fable | Most capable, above Opus, highest cost | Toughest challenges where extra capability pays off |
| Opus | Most capable core family; slowest/priciest of core three | Deep reasoning, complex analysis, multi-step coding, nuanced writing |
| Sonnet | Balance of intelligence, speed, cost | Most production work |
| Haiku | Fastest, cheapest | Classification, extraction, routing, high volume |
- Build a simple eval: 20–30 representative real examples, scored against your definition of good.
- Start at Haiku → Sonnet → Opus; stop at “the cheapest model whose output you’d actually ship.”
response.usagereturns input/output tokens — what billing is based on.for model in ["claude-haiku-4-5", "claude-sonnet-5", "claude-opus-5-5"]: r = client.messages.create(model=model, max_tokens=300, messages=[{"role": "user", "content": prompt}]) print(model, r.usage)- Route per task in one endpoint (e.g., classify with Haiku, draft with Sonnet, RFPs with Opus).
Module 2 — Agents, Tools, and Thinking
The agent loop explained
- An agent = Claude running both sides of the loop autonomously: receive task → pick tool → execute → repeat until done.
- Loop: send messages + tools → Claude returns answer or
tool_use→ your code runs the tool → sendtool_resultback → repeat untilstop_reason == "end_turn".while True: response = client.messages.create(model="claude-sonnet-5", max_tokens=1024, tools=tools, messages=messages) if response.stop_reason == "end_turn": print("".join(b.text for b in response.content if b.type == "text")); break if response.stop_reason == "tool_use": results = [{"type": "tool_result", "tool_use_id": b.id, "content": run_tool(b.name, b.input)} for b in response.content if b.type == "tool_use"] messages.append({"role": "assistant", "content": response.content}) messages.append({"role": "user", "content": results}) - “You own the loop and the tools. Claude owns the reasoning.” Same shape scales to production (real tools, SSE streaming to UI, persisting findings).
What is tool use?
- A tool = a function you define and expose; Claude requests, your code executes.
- Definition = name + description +
input_schema(JSON Schema), passed intools. - Vague descriptions are the #1 reason agents misfire. Claude chooses among tools by reading descriptions.
{ "name": "lookup_building_code", "description": "Look up a specific building code section by its identifier. Returns the full text of that code section.", "input_schema": { "type": "object", "properties": { "section": { "type": "string", "description": "The building code section to look up" } }, "required": ["section"] } } - Multiple tools → dispatch on name (switch). Claude may call several in one turn.
- Tool Runner (beta in TS, Python, Ruby, C#, Go, Java, PHP SDKs) runs the loop for you. In TS,
betaZodTool()+ Zod schemas (validates input too):const weatherTool = betaZodTool({ name: "get_weather", description: "Get today's current weather for a city.", inputSchema: z.object({ city: z.string().describe("The city to check") }), run: async ({ city }) => getWeather(city), }); const finalMessage = await client.beta.messages.toolRunner({ model: "claude-sonnet-5", max_tokens: 1024, messages, tools: [weatherTool], }); - Real tools are thin wrappers around functions already in your codebase.
What is thinking? (extended thinking)
- Claude reasons step by step (chain of thought) before answering — avoids confident wrong answers on multi-step problems.
- On the Opus model shown, thinking is adaptive and on by default — no token budget; Claude decides when/how much.
- Control depth with
effortinsideoutput_config:low | medium | high(default)| xhigh | max. - Reasoning text is hidden unless
thinkingincludes"display": "summarized".response = client.messages.create( model="claude-opus-5", max_tokens=16000, thinking={"type": "adaptive", "display": "summarized"}, output_config={"effort": "high"}, tools=[weather_tool], messages=[...]) - Use for math, multi-step logic, debugging, regulatory analysis, trade-offs. Skip for classification, extraction, boilerplate (adds latency/cost only).
Module 3 — Extending the Agent
Built-in tools
- Server tools (declared by you, run by Anthropic): web search (with citations), code execution (Python sandbox), web fetch. No agent loop needed — results arrive in the same response.
client.messages.create(model="claude-opus-5", max_tokens=1024, tools=[{"type": "web_search_20260209", "name": "web_search"}], messages=[...]) - New block types:
server_tool_use, code-execution result blocks (e.g.,bash_code_execution_tool_result), plus text. - Client tools (schema built into Claude, run by your code): memory (SDK helpers in four SDKs, your storage) and bash (your app runs the shell).
- Always double-check facts — “validated on the internet” ≠ true.
Skills
- Folder with
SKILL.md+ scripts/resources; uploaded once, attached by ID. Tools = what Claude can do; Skills = how you want it done. - Progressive loading: only name + description at start; full Skill when relevant.
skill = client.skills.create(display_name="Status Report Generator", files=files_from_dir("status-report-skill")) response = client.messages.create( model="claude-opus-5", max_tokens=4096, container={"skills": [{"type": "custom", "skill_id": skill.id, "version": "latest"}]}, tools=[{"type": "code_execution_20250825", "name": "code_execution"}], # required messages=[{"role": "user", "content": f"Generate the daily status report from:\n{log}"}]) - Skills are GA (old
skills-2025-10-02beta header no longer required).container.skillsis a list → layer multiple. Code execution is required since Skills run in its container.
MCP
- Solves maintenance: the service provider publishes and updates the MCP server; you change nothing when their API changes.
| Feature | For | Who maintains |
|---|---|---|
| Tools | Your internal systems | You |
| Skills | Your processes/procedures | You (instructions) |
| MCP | Third-party services | Provider |
mcp_serversdeclares connection (type, URL, name, optional token) + anmcp_toolsettool grants access. Beta header required (mcp-client-2025-11-20in lesson). No schemas written — Claude introspects.client.beta.messages.create(model="claude-opus-5", max_tokens=1024, messages=[...], mcp_servers=[{"type": "url", "url": "https://mcp.linear.app/mcp", "name": "linear", "authorization_token": os.environ["LINEAR_MCP_TOKEN"]}], tools=[{"type": "mcp_toolset", "mcp_server_name": "linear"}], betas=["mcp-client-2025-11-20"])- Restrict (e.g., read-only):
"default_config": {"enabled": False}+ enable specific tools in"configs".
Context management
- Context = system prompt + history + tool defs/results + files/skills + thinking. Paid on every call; full window → request fails. Goal: fit the right things.
| Pattern | Type | Solves |
|---|---|---|
| Just-in-time context | Design pattern (pull via tools) | Window size |
| Server-side compaction | API (context_management edit, beta) |
Long conversations |
| Prompt caching | API (mark stable prefix) | Cost |
| Memory tool | API client tool (your storage) | Statelessness across sessions |
client.beta.messages.create(betas=["compact-2026-01-12"], model="claude-opus-5",
max_tokens=1024, context_management={"edits": [{"type": "compact_20260112"}]},
messages=messages)
- Production agents usually layer all four. Managed agents enable caching + compaction by default.
Module 4 — Handing Work Off
What are managed agents?
- Claude Managed Agents: APIs to build/deploy agents whose loop runs on Anthropic’s infrastructure in an isolated container (filesystem, bash, web search). Own section in the Console.
- Examples: Kanban ticket → session with rubric + separate grader iterating to a Lighthouse score; weekly SaaS-pricing research agent with memory, skills, MCP (Slack/Asana); incident response with a coordinator + specialist agents and a permission policy requiring human approval.
- Building blocks: Agents · Sessions · Environments · Tools · MCP · Memory · Outcomes (rubrics/graders) · Multi-agent coordination.
Building your first managed agent
- Four primitives in order: Agent (model, system prompt, toolset; reusable) → Environment (cloud/self-hosted, networking) → Session (one run, unit of work) → Events (in/out stream).
agent = client.beta.agents.create(name="Line Counter", model="claude-opus-5", system="You are a helpful agent that completes small file tasks.", tools=[{"type": "agent_toolset_20260401", "default_config": {"enabled": True}}]) env = client.beta.environments.create(name="line-counter-env", config={"type": "cloud", "networking": {"type": "limited"}}) session = client.beta.sessions.create(agent=agent.id, environment_id=env.id) with client.beta.sessions.events.stream(session_id=session.id) as stream: # open FIRST client.beta.sessions.events.send(session_id=session.id, events=[{"type": "user.message", "content": [{"type": "text", "text": "Create a file in the temp directory, count its lines, and report back."}]}]) for event in stream: if event.type == "agent.message": ... elif event.type == "agent.tool_use": print(event.name) elif event.type == "session.status_idle": break limitednetworking = onlyallowed_hosts;unrestrictedonly when necessary.- Open the stream before sending the kickoff (stream only delivers later events).
- On idle, check
event.stop_reason.type:end_turn(done/interrupted) vsrequires_action(tool call needs your answer). - Event history is server-side → reconnect, list past events, de-dupe.
- Choose managed agents for long-running, file-touching, resumable work; manual loop for full control.
Building with Claude Code
- Stub a file, then let Claude Code fill in the integration. Built-in Claude API skill (
/claude-apior auto-invoked when it detects the SDK). - Good prompt names the file, the pattern (e.g., tool runner), and the end state. Claude writes, runs, fixes errors.
- Pattern: define a tool → hand to a runner → return the result. Stub, delegate, review the diff.
Quick-Review Flashcards
- Q: Three required params of
messages.create? → A:model,max_tokens,messages. - Q: Why loop over
response.content? → A: It’s an array of typed blocks (text, tool_use, thinking…), not a string. - Q: How do you pick a model? → A: Eval 20–30 real examples from Haiku upward; choose the cheapest output you’d ship.
- Q: Which stop reason ends the agent loop? → A:
end_turn(tool_usemeans run tools and continue). - Q: Who executes a custom tool? → A: Your code — Claude only requests it.
- Q: Most common cause of agent tool misfires? → A: Vague tool descriptions.
- Q: Where does the
effortparameter go? → A: Insideoutput_config(low/medium/high/xhigh/max). - Q: Server tools vs client tools? → A: Server tools (web search, code exec, web fetch) run on Anthropic; client tools (memory, bash) have built-in schemas but run in your code.
- Q: Tools vs Skills vs MCP? → A: Your stuff / your processes / everyone else’s stuff.
- Q: What must accompany Skills on the API? → A: The code execution tool (Skills run in its container).
- Q: Four context-management patterns? → A: Just-in-time context, server-side compaction, prompt caching, memory tool.
- Q: Four managed-agent primitives? → A: Agent, Environment, Session, Events — open the stream before sending the kickoff.
Practice Ideas
- Write the ~20-line code-review script in TS, then port it to Python.
- Build a 20-example eval for a real task and compare Haiku/Sonnet/Opus on quality, latency, and
usage. - Hand-write the weather agent loop, then rewrite it with the Tool Runner and compare line counts.
- Add a second and third tool; experiment with vague vs specific descriptions and observe tool choice.
- Toggle adaptive thinking with different
effortlevels on a trade-off question; compare cost and answer quality. - Build a fact-checker using the web search server tool.
- Package your team’s status-report template as a Skill and attach it via
container.skills. - Connect a read-only MCP toolset (default disabled + allowlist).
- Add prompt caching to a long system prompt and measure token savings.
- Create a managed agent that organizes a folder and stream its events; practice reconnecting mid-session.