Learn/Claude Academy: Start your journeyguide

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
  1. Claude 101
  2. Claude Code 101
  3. Introduction to Claude Cowork
  4. Introduction to Claude Tag
  5. Claude Platform 101

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.create call 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.content is an array of blocks (text, tool_use, thinking…) — always loop and check type.
  • 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.usage returns 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 → send tool_result back → repeat until stop_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 in tools.
  • 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 effort inside output_config: low | medium | high (default) | xhigh | max.
  • Reasoning text is hidden unless thinking includes "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-02 beta header no longer required). container.skills is 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_servers declares connection (type, URL, name, optional token) + an mcp_toolset tool grants access. Beta header required (mcp-client-2025-11-20 in 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
  • limited networking = only allowed_hosts; unrestricted only 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) vs requires_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-api or 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

  1. Q: Three required params of messages.create? → A: model, max_tokens, messages.
  2. Q: Why loop over response.content? → A: It’s an array of typed blocks (text, tool_use, thinking…), not a string.
  3. Q: How do you pick a model? → A: Eval 20–30 real examples from Haiku upward; choose the cheapest output you’d ship.
  4. Q: Which stop reason ends the agent loop? → A: end_turn (tool_use means run tools and continue).
  5. Q: Who executes a custom tool? → A: Your code — Claude only requests it.
  6. Q: Most common cause of agent tool misfires? → A: Vague tool descriptions.
  7. Q: Where does the effort parameter go? → A: Inside output_config (low/medium/high/xhigh/max).
  8. 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.
  9. Q: Tools vs Skills vs MCP? → A: Your stuff / your processes / everyone else’s stuff.
  10. Q: What must accompany Skills on the API? → A: The code execution tool (Skills run in its container).
  11. Q: Four context-management patterns? → A: Just-in-time context, server-side compaction, prompt caching, memory tool.
  12. 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 effort levels 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.