Curriculum · Claude Code / Desktop / Cowork

From daily user to Claude power user

Seven phases, one running project. Each phase pairs a Claude capability with a milestone on TaskFlow — an AI-augmented task manager built with a Python backend and a TypeScript frontend — so the practice is never abstract.

FastAPI React + Vite + TS pytest / vitest GitHub Actions Docker Claude API Tool Runner MCP
github.com/nickhargreaves/ClaudePowerUser →

The project: TaskFlow

A small task tracker with one twist — it uses the Claude API itself to triage new tasks. That gives the curriculum a real reason to touch every part of the lifecycle: an API to test, a UI to ship, an LLM call to observe, and a deploy target to watch in production.

7 / 7 phases done
00 Done

Setup — one honest hour

Before any lesson: get the repo, the CLI, and terminal habits in order so later phases aren't fighting the environment.

Follow this phase yourself →

What happened

  • Repo initialized, uv installed for Python tooling
  • backend/ — FastAPI scaffold managed with uv
  • frontend/ — Vite + React + TypeScript scaffold
  • /health wired end-to-end, verified live in the browser

Why it matters

Claude Code reasons about the repo it's sitting in. A clean, committed baseline means every later diff is legible — to you and to Claude.

01 Done

Foundations: talking to Claude Code well

The highest-leverage skill is giving Claude the right context before it writes a line — the habits that separate "prompt and pray" from deliberate collaboration.

Follow this phase yourself →

What happened

  • Wrote a real CLAUDE.md — conventions, commands, gotchas specific to this repo
  • Used plan mode to design the Task data model and CRUD API before writing any code — plan approved, then implemented
  • Backend: models, in-memory TaskStore, /tasks CRUD routes, 6 passing tests

Concepts exercised

  • Plan mode vs. auto-accept
  • Scoping asks: small diffs vs. "build the whole feature"
  • Reading and steering the diff, not just approving it

Milestone hit — a running FastAPI backend and a React shell that lists tasks from it, plus a CLAUDE.md you'd hand to a new teammate.

02 Done

The agentic workflow: skills, subagents, hooks

Where Claude Code stops being "a chatbot with file access" and becomes a configurable system shaped to the project.

Follow this phase yourself →

What happened

  • Wrote /new-endpoint, a project skill that scaffolds a route + model + test + optional frontend wrapper together
  • Used it to build the AI-triage endpoint — Claude tool-use call suggests a priority without mutating the task
  • A PostToolUse hook auto-runs ruff/oxlint on every edit — verified live by watching it silently fix an injected bug
  • Permission allowlist narrowed to the dev loop; destructive actions still prompt
  • An Explore subagent traced a field end-to-end across the stack, citing file:line locations independently

Concepts exercised

  • Custom slash-command skills
  • Hooks: enforcing lint/format automatically
  • Permission modes and narrow allowlists
  • Delegating to a subagent vs. doing it inline

Milestone hit — the AI-triage endpoint exists, built using a self-authored skill.

03 Done

Testing: making Claude prove it, not just claim it

Claude will tell you something works. This phase is about never taking that on faith.

Follow this phase yourself →

What happened

  • Vitest + React Testing Library added to the frontend; API mocked at the boundary, mirroring the backend's mocking pattern
  • A real TDD loop: wrote a failing test for "confirm before delete," watched it fail against the real code, implemented the guard, watched it pass
  • Ran /verify end-to-end in a live browser — found that headless automation auto-accepts native dialogs, a real gap worth knowing

Concepts exercised

  • TDD: failing test first, then made to pass
  • Testing LLM-backed endpoints by mocking the client
  • The verify skill — driving the real flow, not just green tests

Milestone hit — backend and frontend both have a real test suite, including a test that deliberately breaks the Claude call to check the fallback path.

04 Done

CI/CD: Claude as reviewer, not just author

Writing code is half the job. This phase wires Claude into the gate that decides whether code merges.

Follow this phase yourself →

What happened

  • .github/workflows/ci.yml — backend and frontend jobs on every push/PR
  • A real feature, PR #1, exercised it — CI caught a genuine bug (a missing env var) on first run
  • /code-review at medium effort found two confirmed bugs the new feature made more visible; kept out of scope and spawned as a follow-up instead of scope-creeping
  • Branch protection required GitHub Pro on a private repo — made the repo public to unlock it for real, after confirming no secrets were ever committed
  • Enforcement verified for real: a direct push bypassing the PR was rejected by GitHub itself (GH006), routed through PR #2 instead

Concepts exercised

  • GitHub Actions: lint, test, build on every PR
  • /code-review at medium effort
  • Branch protection + required checks so the pipeline isn't advisory

Milestone hit — no PR reaches main without CI green — verified by watching one actually get blocked, for real.

05 Done

Deployment: from laptop to a real URL

Best practice here is less about Claude-specific tricks and more about having Claude execute deployment discipline you'd want from any engineer: reproducible builds, secrets handled correctly, no surprise prod pushes.

Follow this phase yourself →

What happened

  • Two Fly.io apps — taskflow-nh-api (FastAPI/uv) and taskflow-nh-web (Vite build + nginx) — live at taskflow-nh-web.fly.dev
  • nginx reverse-proxies /api/* to the backend server-to-server over Fly's private network — no CORS, and /api/* behaves identically in dev and prod
  • docker-compose.yml for local parity; CD triggers automatically on merge to main
  • /code-review caught two real deploy-breaking bugs before they shipped (a config path bug, an unnecessary job dependency serializing two independent deploys)
  • The guided live deploy then surfaced three more real bugs only visible once actually running — an IPv4-only bind on an IPv6-only private network, nginx's own template auto-substitution colliding with a build-time one, and a static DNS resolution that crashed nginx if the backend was mid-restart — each found by reading the actual error and fixed in turn, verified live afterward

Concepts exercised

  • Dockerizing a FastAPI service and a static frontend build
  • Secrets via Fly (never in the repo or the image) and two least-privilege deploy tokens instead of one broad one
  • Claude proposing risky infra changes and narrating them before acting — a proposed org-wide token and a direct machine scale were both paused for explicit approval

Milestone hit — the app is live at a real URL, deployed by a pipeline, verified working through a real backend restart — not just "the deploy succeeded."

06 Done

Observability: watching an LLM-backed system in the wild

Traditional observability plus one new problem: LLM calls fail silently, drift in latency, and cost real money per request.

Follow this phase yourself →

What happened

  • Structured JSON logging on every request (request id, latency, status) via a FastAPI middleware
  • The triage call traced specifically — tokens, latency, estimated cost, logged on both success and failure
  • A log-based "dashboard" and a simulated alerting script, both reading flyctl logs directly — deliberately no hosted service, no webhook
  • /code-review found six real bugs before any of it shipped, including a log line that could record status="ok" before the model's output was actually validated

What broke, and what happened instead

  • Fly's free trial ended mid-phase, taking down the already-running apps — a billing action left for the human to take, not routed around
  • docker compose up was tried as a cloud-free alternative and genuinely failed too (Docker Desktop's VM wouldn't boot in this sandboxed environment) — abandoned after a real observed failure, not more retries
  • The live incident simulation still happened, just against local dev servers: a real invalid API key was swapped in, three genuine 502s generated, and the dashboard + alerting scripts run cold against the resulting logs — the alert correctly fired at a 100% error rate
  • Root-causing past the alert surfaced a real, previously-unknown gap: the triage log recorded that a call failed but never why — no exception type or message

Milestone hit — the dashboard and alerting scripts correctly diagnosed a real, deliberately-injected incident from logs alone — verified live, not simulated on paper.

07 Done

Going further: MCP servers and multi-agent design

The capstone: build the kind of tool you've been using all along, and use orchestration patterns beyond single-agent chat.

Follow this phase yourself →

What happened

  • A small mcp.server.fastmcp.FastMCP server, stdio transport, exposing TaskFlow's own REST API as six tools — a thin wrapper around the running backend, not a second store
  • Verified through the real MCP protocol via the Inspector, not just imports: tool listing, a full taskflow_create_task call round-tripped and confirmed against the backend directly, and every error path (404, connection-refused, upstream-502) exercised on its own
  • A recurring chore — a weekly triage-usage digest — retired to an actual scheduled Claude agent (not a script run by CI), run once manually first to prove it produces a correct entry before trusting the schedule unattended

The plan said "Agent SDK" — that was wrong

The lesson goal says rebuild triage on the Claude Agent SDK. But that SDK is Claude Code itself, packaged as a library — a full coding-agent harness (file tools, bash, subagents, permissions) for open-ended work. TaskFlow's triage call is one forced-tool classification request, not an agent. That mismatch got caught and confirmed with a human before any code was written, and the rebuild happened on the Anthropic SDK's Tool Runner instead — the right next tier up, honestly assessed as a small real win, not oversold as a rewrite.

Milestone hit — TaskFlow tasks managed live from a real MCP client via a self-written server, and a scheduled agent (not a cron script) produces a weekly digest without being asked.

PhaseClaude surfaceStatus
00 SetupCLI install, repo initdone
01 FoundationsCLAUDE.md, plan modedone
02 Agentic workflowSkills, subagents, hooksdone
03 Testingverify skill, TDD loopdone
04 CI/CD/code-review, branch protectiondone
05 DeploymentGuided deploy, risk narrationdone
06 ObservabilityLog-driven debuggingdone
07 MCP & agentsMCP server, Tool Runner, scheduled agentdone