Build a Task Manager API with Claude Code

Build a Python REST API by directing an AI coding agent with natural language.

Introduction

30 Second Summary

Imagine having a coding partner who can read your entire project, write code across multiple files, run tests, spot errors, and fix them on its own. That's not a fantasy anymore.

In this project, you will build a task manager API using Claude Code, an AI coding agent that lives in your terminal. Instead of writing the code yourself, you'll direct Claude Code with natural language prompts and watch it plan, implement, test, and debug autonomously.

What You'll Build

A fully functional REST API for managing tasks, built in Python with Flask, where Claude Code writes virtually all of the code for you.

By the end of this project, you'll have:

  • A working REST API with endpoints for creating, reading, updating, and deleting tasks.
  • A test suite that Claude Code wrote, ran, and iteratively fixed on its own.
  • A CLAUDE.md file that gives Claude persistent project context, showing you how to guide an AI coding agent effectively.
  • Secret Mission: Add priority filtering and a health endpoint using Claude Code's plan mode to review changes before they touch your files.

Are there any prerequisites?

You should have some coding experience and Git installed on your machine. A code editor (like VS Code or Cursor) is also needed. No prior experience with Claude Code or Flask is required.

Set Up Claude Code on Windows

Claude Code is a terminal-based AI coding agent that reads, writes, and runs code on your behalf. Before it can do anything, it needs a connection to Anthropic's language models.

In this step, you'll create an Anthropic Console account, install the Claude Code CLI, and verify that everything is connected. By the end, typing a prompt in your terminal will return a live AI response.

In this step, get ready to:
  • Create an Anthropic Console account and add credits.
  • Install the Claude Code CLI on Windows.
  • Authenticate and test the connection.
Create an Anthropic Console account

The Anthropic Console is the developer dashboard where you manage API access and billing. You need an account here so Claude Code can call the AI models on your behalf.

  • Open your browser and navigate to console.anthropic.com.
  • Click Continue with Google or Continue with Email to create your account.
  • Once logged in, navigate to the billing section and add at least $5 in credits.

Why $5 in credits?

The Anthropic Console uses pay-per-use pricing. $5 is the minimum credit purchase for Tier 1 access. Every prompt you send through Claude Code consumes a small amount of credit based on the length of your conversation.

  • Navigate to the API Keys section in your account settings.
  • Click Create Key to generate a new API key.
  • Copy your API key immediately and store it somewhere secure. You will not be able to see the full key again after leaving this page.

What is an API key?

An API key is a unique credential that identifies your account when making requests to Anthropic's models. Think of it like a password that lets Claude Code access the AI on your behalf.

Never share your API key publicly or commit it to version control. Anyone with your key can use your credits.

Install Claude Code on Windows

Claude Code is a CLI tool that runs directly in your terminal. You install it using a single PowerShell command.

  • Press the Windows key to open your search bar.
  • Type PowerShell and press Enter to open it.
  • Install Claude Code by running this command:
irm https://claude.ai/install.ps1 | iex

What does this command do?

This command downloads and runs the official Claude Code installer from Anthropic's servers. irm fetches the install script, and iex executes it. The native installation also auto-updates in the background to keep you on the latest version.

  • Close this PowerShell window and open a new one (the current window will not recognize the newly installed command).
  • Verify the installation succeeded by running:
claude --version

✔️ I see a version number

Claude Code is installed and ready. You can move on to the next substep.

ⓧ Command not found

The command is not recognized. Try these fixes:

  • Make sure you opened a brand new PowerShell window after the install completed. The old window does not pick up newly installed commands.
  • Try running the install command again in the new window. If it fails, check your internet connection and ensure no firewall is blocking the download.
  • If you are still stuck, try the alternative install method using WinGet:
winget install Anthropic.ClaudeCode

After installing with either method, close and reopen PowerShell, then run claude --version again.

Git for Windows unlocks extra features

Since you already have Git installed, Claude Code can use the Bash tool in addition to PowerShell. This gives it more flexibility when running shell commands on your behalf.

Authenticate Claude Code

Now that Claude Code is installed, you need to connect it to your Anthropic Console account so it can use your credits to call the AI models.

  • In your PowerShell window, start Claude Code by running:
claude

What happens next?

On first launch, Claude Code opens a browser window for you to log in. If the browser does not open automatically, press c to copy the login URL to your clipboard, then paste it into your browser manually.

  • When prompted to choose an authentication method, select Anthropic Console as your provider.
  • Complete the login flow in your browser using the same credentials you used to create your Console account.

What is the Claude Code workspace?

On first login with Console credentials, a workspace called "Claude Code" is automatically created in your Anthropic Console. This workspace provides centralized cost tracking for all your Claude Code usage.

  • Once authenticated, you should be back in your terminal with Claude Code ready for input. Test the connection by typing:
hello
  • Confirm that Claude responds with a greeting or helpful message. Any response means the connection is working.

Not getting a response?

  • If authentication failed, check that your Console account has credits loaded. A $0 balance means API calls cannot go through.
  • If you see a network error, check your internet connection and ensure no VPN or firewall is blocking access to Anthropic's servers.
  • If you chose the wrong provider during setup, type /login inside Claude Code to restart the authentication flow.

Help me troubleshoot my Claude Code authentication

Your development environment is ready. Claude Code is installed, authenticated, and responding to prompts. Next up, you'll initialize your project and teach Claude about your coding conventions using a CLAUDE.md file.

Initialize Your Project with CLAUDE.md

Claude Code is installed and ready to go. Now you need to give it a project to work in.

Every effective AI coding agent needs context about the project it is working on. In this step, you will create a project directory and give Claude a CLAUDE.md file that tells it your coding conventions, tech stack, and project structure. This file is read automatically at the start of every conversation, so Claude always knows how your project works.

In this step, get ready to:
  • Create your project directory and initialize a Git repository.
  • Create and configure a CLAUDE.md file with project conventions.
  • Verify Claude references your conventions from memory.
Create your project directory and initialize Git

Before Claude Code can build anything, it needs a project folder with version control. Git tracks every change Claude makes, giving you a full history to review or revert.

  • Press the Windows key to open your search bar.
  • Type PowerShell and press Enter to open it.
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder, move into it, and initialize a Git repository by running these commands:
mkdir task-manager-api
cd task-manager-api
git init

What do these commands do?

  • mkdir task-manager-api creates a new folder called task-manager-api on your Desktop.
  • cd task-manager-api moves your terminal into that folder.
  • git init turns the folder into a Git repository so all changes are tracked.
  • Confirm the folder was created by running:
ls

You should see an empty directory (or just a hidden .git folder if hidden items are visible).

  • Start Claude Code inside your project by running:
claude

Claude Code opens an interactive session in your terminal. You should see a prompt where you can type messages to Claude.

Claude not starting?

  • If you see a "command not found" error, try closing and reopening PowerShell. The install from Step 1 requires a fresh terminal session to register the command.
  • If you see an authentication error, run claude again and follow the login prompts to reconnect your Anthropic Console account.

Help me troubleshoot why Claude Code won't start in my PowerShell terminal.

Create a CLAUDE.md file with project conventions

CLAUDE.md is a special file that Claude reads at the start of every conversation. It holds your project conventions, tech stack, and coding rules so Claude does not need you to repeat them each time.

  • Inside your Claude Code session, generate a starter CLAUDE.md by typing this command:
/init

What does /init do?

The /init command analyzes your project and generates a starter CLAUDE.md file based on what it finds. Since your project is empty right now, the generated file will be minimal. You will update it next with your specific conventions.

Claude will create the file and ask for your approval. Approve the change.

  • Now tell Claude to update the file with your project conventions by typing this prompt:
Update CLAUDE.md with the following project conventions: this is a Python Flask REST API for managing tasks. Use pytest for testing. Follow PEP 8 style. Keep all source code in an app/ directory with tests in tests/. Use in-memory storage with a dictionary keyed by task ID. All endpoints should return proper HTTP status codes and JSON responses.

Why be this specific in your prompt?

The more detail you give Claude about your conventions upfront, the less correcting you will do later. Every convention in CLAUDE.md is context Claude uses when writing code, choosing patterns, and structuring files.

  • Review the changes Claude proposes to CLAUDE.md.
  • Approve the file changes when Claude asks for permission.

Claude's output may vary slightly

Claude Code is an AI agent, so its exact wording may differ from the reference below. The important thing is that your CLAUDE.md covers: Python with Flask, pytest for testing, PEP 8 style, source in app/ directory, tests in tests/ directory, in-memory storage, proper HTTP status codes, and JSON responses.

✔️ Awesome, I've got everything!

Great. Double check you have approved the file changes before moving on.

ⓧ I'd like to double check the full code

Your CLAUDE.md should contain content similar to this:

# Task Manager API

## Project Overview
A Python Flask REST API for managing tasks.

## Tech Stack
- Python with Flask
- pytest for testing
- In-memory storage (dictionary keyed by task ID)

## Conventions
- Follow PEP 8 style
- Source code in app/ directory
- Tests in tests/ directory
- Use proper HTTP status codes
- Return JSON responses for all endpoints
Verify Claude has absorbed your project context

The whole point of CLAUDE.md is that Claude remembers your conventions without you repeating them. Let's confirm it works.

  • Ask Claude this question in your session:
what are the coding conventions for this project?

Claude should respond by referencing your CLAUDE.md contents. You should see it mention PEP 8, Flask, pytest, the app/ directory, and the tests/ directory without you repeating any of that information.

Why does this matter?

This confirms Claude is reading your CLAUDE.md at the start of the conversation. From now on, every time you give Claude a task, it already knows your tech stack, style preferences, and directory structure. You can focus on describing WHAT to build instead of HOW to structure it.

Claude not referencing your conventions?

  • Make sure you approved the CLAUDE.md file changes in the previous substep. If you skipped approval, the file was not saved.
  • Check that CLAUDE.md is in the root of your task-manager-api folder, not inside a subdirectory.

Claude isn't referencing my CLAUDE.md conventions when I ask about the project. Help me debug this.

Your project now has a Git repository and a CLAUDE.md that gives Claude persistent memory of your conventions. Next up, you will put Claude to work building the actual API with nothing but natural language prompts.

Build the API with Claude Code's Agentic Loop

Your project directory is ready and Claude Code already knows your conventions from CLAUDE.md. Now it's time to build the actual API without writing any code yourself.

You'll give Claude Code natural language prompts and watch it plan, create files, and wire everything together autonomously. This is the agentic loop in action. Claude reads your context, proposes changes, executes them across multiple files, and asks you to approve each modification.

In this step, get ready to:
  • Scaffold the project structure with models, routes, and an app factory.
  • Implement full CRUD endpoints for task management.
  • Verify the Flask server starts without errors.
Scaffold the project structure

Before Claude Code can build endpoints, it needs a project skeleton. Files, folders, a data model, and a Flask app factory all need to exist first.

  • In your Claude Code session, type this prompt and press Enter:
Set up a Python Flask REST API for managing tasks. Create the project structure with app/__init__.py, app/routes.py, app/models.py, and requirements.txt. A task has an id, title, description, status (todo/in-progress/done), and created_at timestamp. Use an in-memory dictionary keyed by task ID for storage.

What is Claude Code doing?

Watch your terminal carefully. Claude Code reads your CLAUDE.md first to understand project conventions, then proposes a plan for the file structure.

It creates each file one at a time, explaining its approach before writing. For each file change, Claude Code pauses and asks you to approve the modification.

You should see Claude Code create four files: app/__init__.py, app/models.py, app/routes.py, and requirements.txt.

  • Approve each file change when Claude Code asks for permission.

Claude Code asking too many questions instead of acting?

If Claude keeps asking clarifying questions instead of creating files, try rephrasing your prompt to be more specific. Include the exact filenames and structure you want.

You can also type "go ahead and create the files" to nudge it into action mode.

Help me get Claude Code to generate files instead of asking questions

Add the CRUD endpoints

The skeleton is in place, but the route handlers are either empty or only partially implemented. Claude Code needs a focused prompt to build out the full REST API with proper status codes and error handling.

  • Type this prompt in your Claude Code session:
Add REST endpoints: GET /tasks (list all), GET /tasks/<id> (get one), POST /tasks (create), PUT /tasks/<id> (update), DELETE /tasks/<id> (delete). Return proper HTTP status codes and JSON responses.

How does Claude Code handle multi-file changes?

Notice how Claude reads your existing files before making changes. It checks app/models.py to understand the data model, then modifies app/routes.py to add handlers that call the right model functions.

This context awareness is what makes agentic coding different from simple code completion. Claude Code works across files like a human developer would.

Claude Code updates app/routes.py with all five endpoint handlers and may also update app/models.py if any helper functions are missing.

  • Approve each file change when prompted.

Claude Code only created some endpoints?

If Claude didn't implement all five endpoints in one pass, give it a follow-up prompt: "Also add the PUT and DELETE endpoints" (naming whichever are missing).

Claude Code sometimes splits large changes into multiple rounds. This is normal behavior.

Help me get Claude Code to implement all my REST endpoints

Run the app to verify it works

You have models and routes, but no entry point to actually start the server. Claude Code can create run.py and launch Flask to confirm everything wires together without errors.

  • Type this prompt in your Claude Code session:
Create a run.py entry point and start the Flask server briefly to verify it runs without errors.
  • Approve the file creation for run.py.
  • When Claude Code asks permission to execute the server command, approve it.

You should see Flask start on port 5000 with output similar to "Running on http://127.0.0.1:5000". Claude Code will stop the server automatically after verifying it starts.

Server didn't start?

If you see an import error, Claude Code likely created the files in a slightly different structure than expected. Ask Claude: "Fix the import error and try running the server again." It will read the error, identify the cause, and fix it autonomously.

If Flask is not installed, ask Claude: "Install the requirements first, then run the server."

Help me fix my Flask server startup error in Claude Code

Your code might look slightly different

Claude Code is non-deterministic. Variable names, comment styles, or function ordering might differ from the reference code below. That is completely fine as long as the API behavior is the same.

If your code differs significantly (missing endpoints, wrong status codes, or different file structure), ask Claude to adjust: "Update the code to match PEP 8 style and ensure all five CRUD endpoints exist."

✔️ Awesome, I've got everything!

Great. Double check you have all five files: CLAUDE.md, app/__init__.py, app/models.py, app/routes.py, requirements.txt, and run.py.

ⓧ I'd like to double check the full code

Compare your generated code against these reference files. Minor style differences are fine. Focus on matching the structure, function names, and endpoints.

from flask import Flask


def create_app():
    app = Flask(__name__)

    from app.routes import tasks_bp
    app.register_blueprint(tasks_bp)

    return app
from datetime import datetime, timezone

tasks_db = {}
next_id = 1


def get_all_tasks():
    return list(tasks_db.values())


def get_task(task_id):
    return tasks_db.get(task_id)


def create_task(title, description="", status="todo"):
    global next_id
    task = {
        "id": next_id,
        "title": title,
        "description": description,
        "status": status,
        "created_at": datetime.now(timezone.utc).isoformat(),
    }
    tasks_db[next_id] = task
    next_id += 1
    return task


def update_task(task_id, data):
    task = tasks_db.get(task_id)
    if task is None:
        return None
    if "title" in data:
        task["title"] = data["title"]
    if "description" in data:
        task["description"] = data["description"]
    if "status" in data:
        if data["status"] not in ("todo", "in-progress", "done"):
            return "invalid_status"
        task["status"] = data["status"]
    return task


def delete_task(task_id):
    if task_id in tasks_db:
        del tasks_db[task_id]
        return True
    return False


def clear_tasks():
    global next_id
    tasks_db.clear()
    next_id = 1
from flask import Blueprint, request, jsonify
from app.models import get_all_tasks, get_task, create_task, update_task, delete_task

tasks_bp = Blueprint("tasks", __name__)


@tasks_bp.route("/tasks", methods=["GET"])
def list_tasks():
    tasks = get_all_tasks()
    return jsonify(tasks), 200


@tasks_bp.route("/tasks/<int:task_id>", methods=["GET"])
def get_single_task(task_id):
    task = get_task(task_id)
    if task is None:
        return jsonify({"error": "Task not found"}), 404
    return jsonify(task), 200


@tasks_bp.route("/tasks", methods=["POST"])
def create_new_task():
    data = request.get_json()
    if not data or "title" not in data:
        return jsonify({"error": "Title is required"}), 400
    task = create_task(
        title=data["title"],
        description=data.get("description", ""),
        status=data.get("status", "todo"),
    )
    return jsonify(task), 201


@tasks_bp.route("/tasks/<int:task_id>", methods=["PUT"])
def update_existing_task(task_id):
    data = request.get_json()
    if not data:
        return jsonify({"error": "Request body is required"}), 400
    result = update_task(task_id, data)
    if result is None:
        return jsonify({"error": "Task not found"}), 404
    if result == "invalid_status":
        return jsonify({"error": "Invalid status. Must be todo, in-progress, or done"}), 400
    return jsonify(result), 200


@tasks_bp.route("/tasks/<int:task_id>", methods=["DELETE"])
def delete_existing_task(task_id):
    success = delete_task(task_id)
    if not success:
        return jsonify({"error": "Task not found"}), 404
    return jsonify({"message": "Task deleted"}), 200
flask==3.1.1
pytest==8.3.5
from app import create_app

app = create_app()

if __name__ == "__main__":
    app.run(debug=True, port=5000)

Your API is scaffolded and the server runs cleanly. Next up, you'll have Claude Code write a full test suite and then watch it autonomously fix any failures it finds.

Test-Driven Iteration with Claude Code

Your API is built and running. Now you need to prove it actually works correctly across all edge cases.

In this step, you will ask Claude Code to write a comprehensive test suite and then run it. If any tests fail, Claude Code enters an autonomous fix loop. It reads the error output, identifies the root cause, edits the source code, and reruns the tests until everything passes.

In this step, get ready to:
  • Have Claude Code write comprehensive pytest tests for all endpoints.
  • Watch Claude Code's autonomous test-fix loop in action.
  • Commit the passing test suite to Git.
Prompt Claude to write tests

A test suite exercises every endpoint with both valid and invalid inputs. It proves your API handles success cases, error cases, and edge cases correctly.

  • In your Claude Code session, type the following prompt and press Enter:
Write comprehensive pytest tests for all task endpoints. Cover success cases, error cases (404 for missing tasks, 400 for invalid input), and edge cases. Put tests in tests/test_routes.py.

What does this prompt do?

This prompt tells Claude Code exactly what test coverage you need and where to put the test file. Claude reads your existing CLAUDE.md to know you use pytest and keep tests in the tests/ directory.

Watch as Claude creates tests/__init__.py and tests/test_routes.py. It reads your route handlers and models to understand what each endpoint expects, then writes tests that exercise each one.

  • Claude will ask for approval before creating each file. Review the proposed test code and approve it.
  • After approval, you should see Claude confirm that both tests/__init__.py and tests/test_routes.py have been created.

What should I see in the tests?

Claude should generate test functions covering empty task lists, creating tasks with valid and invalid data, getting tasks by ID, updating tasks with valid and invalid status values, and deleting tasks. Each test uses a Flask test client and the clear_tasks() helper to reset state between runs.

Claude used a different test framework?

If Claude proposes unittest instead of pytest, remind it of your project conventions by saying: "Use pytest as specified in CLAUDE.md." Claude will rewrite the tests.

Help me get Claude Code to follow my CLAUDE.md conventions for testing.

Run the tests and watch Claude fix failures

This is where Claude Code shows its full power as an agentic tool. You give it one instruction and it loops autonomously: running tests, reading errors, editing code, and retrying until all tests pass.

  • Type the following prompt in Claude Code and press Enter:
Run the tests with pytest and fix any failures.
  • Approve the command execution when Claude asks to run pytest.
  • Watch the entire loop without intervening. Claude will run the test suite, read any error output, identify root causes, edit the source code, and rerun the tests.
  • Wait until Claude reports that all tests pass. You should see a pytest summary showing all tests with a green PASSED status.

Why is this different from a code completion tool?

A code completion tool suggests the next line of code. Claude Code runs entire workflows autonomously. It executes shell commands, reads their output, decides what to fix, makes the fix, and verifies the fix worked. You did not tell it which files to edit or what the errors meant.

This is agentic coding. The AI handles the full feedback loop while you stay in the driver's seat, approving or rejecting each action.

Claude seems stuck in a loop?

If Claude keeps failing the same test repeatedly, press Escape to stop it. Then give a more specific prompt like: "The test_create_task_empty_body test is failing because the endpoint does not handle an empty JSON body. Fix the POST /tasks endpoint to return 400 when the body has no title field."

Help me get Claude Code unstuck on a failing test.

Commit the working code

With all tests green, you want to save this state in Git so you have a clean checkpoint to return to later.

  • Type the following prompt in Claude Code:
Commit all changes with a descriptive message.
  • Approve the command when Claude runs git add and git commit.
  • Review the commit message Claude generates. It should describe both the test suite and any fixes it made during the iteration loop.

What does a good commit message look like?

Claude typically generates something like "Add comprehensive pytest test suite for task API endpoints" or similar. The message should reference what was added (tests) and optionally what was fixed. If the message is too vague, you can ask Claude to rewrite it before approving.

Claude committed without asking?

If you have previously approved Git commands in this session, Claude may auto-approve similar ones. This is normal. Check the commit was made by looking at the output. You should see a line starting with a commit hash and the message.

Help me understand Claude Code's permission system for Git commands.

✔️ Awesome, I've got everything!

Great. Confirm your commit went through by checking that Claude showed you the commit hash and message.

ⓧ I'd like to double check the full code

Here is what tests/test_routes.py should look like. Your version may have minor formatting differences since Claude Code generated it, but the test functions and assertions should match:

import pytest
from app import create_app
from app.models import clear_tasks


@pytest.fixture
def client():
    app = create_app()
    app.config["TESTING"] = True
    with app.test_client() as client:
        clear_tasks()
        yield client


def test_list_tasks_empty(client):
    response = client.get("/tasks")
    assert response.status_code == 200
    assert response.get_json() == []


def test_create_task(client):
    response = client.post("/tasks", json={"title": "Test task", "description": "A test"})
    assert response.status_code == 201
    data = response.get_json()
    assert data["title"] == "Test task"
    assert data["description"] == "A test"
    assert data["status"] == "todo"
    assert "id" in data
    assert "created_at" in data


def test_create_task_missing_title(client):
    response = client.post("/tasks", json={"description": "No title"})
    assert response.status_code == 400


def test_create_task_empty_body(client):
    response = client.post("/tasks", content_type="application/json", data="{}")
    assert response.status_code == 400


def test_get_task(client):
    client.post("/tasks", json={"title": "Find me"})
    response = client.get("/tasks/1")
    assert response.status_code == 200
    assert response.get_json()["title"] == "Find me"


def test_get_task_not_found(client):
    response = client.get("/tasks/999")
    assert response.status_code == 404


def test_update_task(client):
    client.post("/tasks", json={"title": "Original"})
    response = client.put("/tasks/1", json={"title": "Updated", "status": "done"})
    assert response.status_code == 200
    data = response.get_json()
    assert data["title"] == "Updated"
    assert data["status"] == "done"


def test_update_task_not_found(client):
    response = client.put("/tasks/999", json={"title": "Nope"})
    assert response.status_code == 404


def test_update_task_invalid_status(client):
    client.post("/tasks", json={"title": "Task"})
    response = client.put("/tasks/1", json={"status": "invalid"})
    assert response.status_code == 400


def test_delete_task(client):
    client.post("/tasks", json={"title": "Delete me"})
    response = client.delete("/tasks/1")
    assert response.status_code == 200
    response = client.get("/tasks/1")
    assert response.status_code == 404


def test_delete_task_not_found(client):
    response = client.delete("/tasks/999")
    assert response.status_code == 404


def test_list_tasks_with_items(client):
    client.post("/tasks", json={"title": "Task 1"})
    client.post("/tasks", json={"title": "Task 2"})
    response = client.get("/tasks")
    assert response.status_code == 200
    data = response.get_json()
    assert len(data) == 2

You now have a full test suite proving every endpoint works correctly, written and verified entirely by Claude Code. Next up, you will use checkpoints to safely explore a risky refactor.

Use Checkpoints to Explore Safely

You have a working API with all tests passing and code committed to Git. What happens when you want to try a risky refactoring that might break everything?

Claude Code creates automatic checkpoints before every code change. If a refactoring goes sideways, you can rewind to the last safe state in seconds. In this step, you'll ask Claude to refactor your storage layer and use checkpoints as your safety net.

In this step, get ready to:
  • Ask Claude Code to refactor your storage layer across multiple files.
  • Use checkpoints to rewind if the refactoring breaks your tests.
  • Commit the final working code and get a project summary from Claude.
Ask Claude to make a risky change

Refactoring code that touches multiple files is where things can go wrong fast. Claude Code automatically creates a checkpoint before it starts editing, so you can always revert.

  • In your Claude Code session, type the following prompt and press Enter:
Refactor the in-memory storage to use a dictionary keyed by task ID instead of a list, and update all endpoints accordingly.

What happens when you send this?

Claude reads your existing code, notices that tasks_db is already a dictionary, and updates any remaining list-like patterns in your endpoints. Before making any file changes, Claude Code saves a checkpoint of your current code state automatically.

Watch the output as Claude explains its approach and asks for approval on each file change. Approve the changes when prompted.

Checkpoints are automatic

You do not need to create checkpoints manually. Claude Code snapshots your files before every edit, so you always have a restore point ready.

Run the tests and rewind if needed

The real test of any refactoring is whether your existing test suite still passes. This is where the checkpoint workflow shines.

  • Tell Claude to run the tests by typing this prompt:
Run the tests.

What should I see?

Claude runs pytest and shows you the test results. If all 12 tests pass, the refactoring is successful. If any tests fail, you have two options for rewinding.

✔️ All tests pass

The refactoring worked. Claude updated the code without breaking anything. You can move on to committing.

ⓧ Some tests fail

This is exactly what checkpoints are for. You can rewind to the state before Claude made changes and try a different approach.

  • Press Esc twice to rewind to the last checkpoint. This restores both your code and conversation to the previous state.
  • Alternatively, type /rewind and choose to restore code only (keeping the conversation). This lets you try a different prompt while remembering what went wrong.
  • After rewinding, try a different approach by typing this prompt:
Try the refactoring again, but this time update the test assertions first to match the new storage format.

Claude approaches the problem differently this time. Approve the changes and run the tests again until they all pass.

Stuck in a loop of failing tests?

If Claude keeps producing code that fails tests after multiple attempts, use /rewind to go back to the last fully passing state. Then try a more specific prompt that tells Claude exactly which file to change first.

help me rewind to a working state and try the refactoring with a different strategy

Commit the refactoring and get a summary

Once all tests pass, you want to lock in the working state with a Git commit. Then you can ask Claude for a full summary of everything you built together.

  • Tell Claude to commit the refactoring by typing this prompt:
Commit the refactoring with a message explaining the storage change.
  • Review the commit message Claude generates. It should describe the storage refactoring clearly.
  • Approve the commit when prompted.

Why let Claude write commit messages?

Claude has full context of every change it made and why. Its commit messages tend to be more descriptive than what you might write manually, because it can reference the exact intent behind each file change.

  • Now ask Claude to summarize the entire project by typing this prompt:
Summarize what we built and what tests cover.

Claude provides a complete overview of your API endpoints, the test coverage, and the project structure. This confirms the final state of everything you built together.

You now know how to use Claude Code's checkpoints to safely explore risky changes without fear of losing working code. Next up, you'll take this further with plan mode in the Secret Mission.

Secret mission

Add Priority Filtering with Plan Mode

Your API handles basic CRUD, but real task managers let you filter and sort. In this mission, you'll use Claude Code's plan mode to add priority filtering, status filtering, and a health endpoint. The twist: you'll review Claude's proposed changes before a single file is modified, simulating a senior engineer reviewing AI-generated code.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally with no cloud services left running. Your Anthropic Console credits are pre-paid and only consumed when you actively use Claude Code, so there are no ongoing costs from leaving things as they are.

Decide whether to keep your resources ready for future Claude Code projects, pause by exiting your session, or delete everything entirely.

Resources you used:

  • task-manager-api/ project folder on your Desktop.
  • Claude Code CLI installed via PowerShell.
  • Anthropic Console API key (used for Claude Code authentication).

Keep everything running

No action needed. Choose this if you plan to keep experimenting with Claude Code or want to extend this API further.

  • Your project files stay on your Desktop in the task-manager-api/ folder.
  • Claude Code remains installed and ready to use in any project directory.
  • Your Anthropic Console credits remain available for future use. You are only charged when you actively run Claude Code.

Pause - I'll come back to this later

Exit your Claude Code session to free up terminal resources. Your project files and credentials stay intact for next time.

  • Type /exit in the Claude Code session or press Ctrl+C to quit.
  • If your Flask dev server is running in another terminal, press Ctrl+C there too.
  • Your project files, Git history, and API key remain saved. Run claude from inside your task-manager-api/ folder to pick up where you left off.

Delete - I don't want to use this again

Remove all project files, uninstall Claude Code, and disable your API key.

  • Exit Claude Code by typing /exit or pressing Ctrl+C.
  • Delete the project folder by running this command in PowerShell:
Remove-Item -Path "$env:USERPROFILE\Desktop\task-manager-api" -Recurse -Force
  • Uninstall Claude Code by running these commands in PowerShell:
Remove-Item -Path "$env:USERPROFILE\.local\bin\claude.exe" -Force
Remove-Item -Path "$env:USERPROFILE\.local\share\claude" -Recurse -Force
  • Remove Claude Code settings and cached data:
Remove-Item -Path "$env:USERPROFILE\.claude" -Recurse -Force
Remove-Item -Path "$env:USERPROFILE\.claude.json" -Force
  • Disable your API key in the Anthropic Console. Go to console.anthropic.com, click Settings, then API Keys. Find the key you created and click Disable to revoke it.

Nice Work!

Nice Work!

Nice work! You just built a fully functional task manager REST API without writing the code yourself.

You directed Claude Code with natural language prompts and watched it plan, implement, test, and debug autonomously.

You've learned how to:

  • Build a complete REST API with CRUD endpoints by directing an AI coding agent with natural language prompts.
  • Create a CLAUDE.md file to give Claude persistent project context and coding conventions that carry across sessions.
  • Use Claude Code's autonomous test-driven iteration loop and checkpoints to safely explore refactoring and rewind when needed.
  • Secret Mission: Used plan mode to review AI-generated changes before they touch disk, simulating code review of an AI agent.

Ready to quiz yourself?