Build an AI Document Summarizer

Use the Claude API and Python to summarize any text file into structured output.

Introduction

30 Second Summary

We all deal with long documents. Meeting notes, reports, email threads. Reading through all of them takes time you could spend on actual work.

In this project, you will build a Python command-line tool that reads any text file and uses Claude to produce a structured summary in seconds.

What You'll Build

A Python CLI tool called summarize.py that sends document text to the Anthropic Messages API and returns a structured summary with a TL;DR, key points, and action items.

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

  • A working Python script that calls the Claude API to summarize any text file.
  • A crafted system prompt that produces consistent, structured output every time.
  • A command-line interface that accepts a filename as an argument and handles errors gracefully.
  • Secret Mission: multiple summary styles (brief, detailed, executive) selectable with a command-line flag.

Are there any prerequisites?

You need basic Python knowledge (variables, functions, strings) and an Anthropic API key. You will install the Anthropic Python SDK during Step 1.

Set Up Your Python Environment

Before you can build an AI-powered tool, you need to connect your local machine to the AI model.

In this step, you'll install the Anthropic Python SDK, set your API key as an environment variable, and confirm everything works.

In this step, get ready to:
  • Install the Anthropic Python SDK.
  • Set the ANTHROPIC_API_KEY environment variable in your terminal.
  • Verify the installation works with an import check.
Install the Anthropic Python SDK

The Anthropic Python SDK is the official library that lets your Python code communicate with Claude.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type VS Code and press Enter to open it.
  • Open the integrated terminal by clicking Terminal in the top menu bar, then New Terminal.
  • Install the Anthropic SDK by running this command:
pip install anthropic

You should see output showing the package downloading and installing successfully, ending with a line like Successfully installed anthropic-....

What is pip?

pip is Python's package installer. It downloads libraries from the Python Package Index (PyPI) so you can use them in your projects.

Seeing 'command not found' or a permission error?

  • If you see pip: command not found, try pip3 install anthropic instead. Some systems use pip3 for Python 3.
  • If you see a permission error, try pip install --user anthropic to install without admin privileges.
  • Make sure you have Python 3.9 or higher installed. Check with python --version.

Help me troubleshoot my pip install error

Set your API key as an environment variable

The Anthropic SDK needs an API key to authenticate your requests to Claude.

Instead of pasting your key directly into code, you'll store it as an environment variable. The SDK reads this variable automatically when it initializes.

macOS

  • In the same VS Code terminal, set your API key by running this command:
export ANTHROPIC_API_KEY='your-api-key-here'
  • Replace your-api-key-here with your actual Anthropic API key. Keep the single quotes around it.

Windows

  • In the same VS Code terminal (PowerShell), set your API key by running this command:
$env:ANTHROPIC_API_KEY = "your-api-key-here"
  • Replace your-api-key-here with your actual Anthropic API key. Keep the double quotes around it.

Why use an environment variable?

Environment variables keep secrets out of your code. If you ever share or publish your script, your API key won't be exposed.

This variable only lasts for your current terminal session. You'll need to set it again if you close and reopen the terminal.

Verify the installation

A quick import check confirms that the SDK installed correctly and Python can find it.

  • Confirm the installation by running this command:
python -c "import anthropic; print('Setup complete!')"

You should see Setup complete! printed in your terminal. This confirms the anthropic package is installed and importable.

Seeing ModuleNotFoundError?

  • If you see ModuleNotFoundError: No module named 'anthropic', the package didn't install for the Python version you're running.
  • Try python3 -c "import anthropic; print('Setup complete!')" to use Python 3 explicitly.
  • If you used pip3 to install, use python3 to run. They need to match.

Help me fix my Python import error

Your environment is ready. Next up, you'll make your first API call to Claude and see a response come back.

Make Your First API Call

Your Python environment is ready and the Anthropic SDK is installed. Now it is time to send your first message to Claude and see what comes back.

Every AI-powered application follows the same core pattern: send a prompt to an API, get a response, and do something with it. In this step, you will write a small test script that proves this pattern works end to end.

In this step, get ready to:
  • Create a test script that sends a simple message to Claude Haiku 4.5.
  • Run it and examine the response object structure.
  • Understand how messages, roles, and content blocks work.
Create your test script

The Anthropic Messages API is the endpoint your script will talk to. You send it a list of messages (with roles like "user" and "assistant") and it sends back Claude's response as structured content blocks.

  • In VS Code, create a new file called test_api.py in your project folder.
  • Copy the following code into test_api.py:
import anthropic

# Create a client (reads ANTHROPIC_API_KEY from your environment automatically)
client = anthropic.Anthropic()

# Send a message to Claude Haiku 4.5
message = client.messages.create(
    model="claude-haiku-4-5",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "Say hello!"}
    ],
)

# Print the text from Claude's response
print(message.content[0].text)

What does this code do?

  • anthropic.Anthropic() creates a client that automatically reads your ANTHROPIC_API_KEY environment variable. No need to pass the key manually.
  • client.messages.create() sends a message to the model you specify. Here you are using claude-haiku-4-5, the fastest and cheapest Claude model.
  • The messages list holds the conversation. Each message has a role ("user" or "assistant") and content (the text of the message).
  • message.content[0].text extracts the text from Claude's response. The response comes as a list of content blocks, and you grab the text from the first block.
  • Save test_api.py.
Run the script and examine the response
  • Run your test script by entering this command in your Terminal:
python test_api.py

You should see a friendly greeting from Claude printed in your terminal. Something like "Hello! How can I help you today?" (the exact wording varies each time).

How does the response object work?

When Claude responds, the API returns a Message object. The actual text is not at the top level. It is nested inside a list of content blocks.

message.content is a list because Claude can return multiple blocks (text, images, tool calls). For simple text responses, you always access the first block with message.content[0].text.

Seeing an authentication error?

  • Make sure your ANTHROPIC_API_KEY environment variable is set in the same Terminal session where you run the script. If you opened a new Terminal window, you need to set it again.
  • Double check that your API key starts with sk-ant- and has no extra spaces or quotes around it.
  • If you see ModuleNotFoundError: No module named 'anthropic', run pip install anthropic again in this Terminal session.

Why is my API call failing?

✔️ Awesome, I've got everything!

Great. Double check you have saved test_api.py and that your script printed a response from Claude.

ⓧ I'd like to double check the full code

Here is the complete test_api.py file for comparison:

import anthropic

client = anthropic.Anthropic()

message = client.messages.create(
    model="claude-haiku-4-5",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "Say hello!"}
    ],
)

print(message.content[0].text)

You just proved the entire pipeline works. Your script sends a prompt, Claude responds, and you extract the text. Next up, you will build a real summarizer by adding a system prompt that tells Claude exactly how to format its output.

Build the Structured Summarizer

In the previous step, you made your first API call to Claude and saw how the response comes back as a message object. Now it's time to put that knowledge to work on a real task.

The real power of AI APIs comes from system prompts. These are special instructions that shape how the model responds every time. In this step, you'll craft a system prompt that turns Claude into a consistent, structured document summarizer.

In this step, get ready to:
  • Write a system prompt that produces structured output with three sections.
  • Create a Python script that reads files and sends them to Claude.
  • Build a sample text file to test your summarizer.
Design your system prompt

A system prompt is a set of instructions you give the model before the user's message. It defines the model's role, tone, and output format for every response.

Your system prompt will instruct Claude to always produce three sections when summarizing a document:

  • TL;DR - a single sentence capturing the entire document.
  • Key Points - a bullet list of the 3-5 most important facts.
  • Action Items - any tasks, decisions, or follow-ups mentioned in the text.

Why use a system prompt instead of putting instructions in the user message?

System prompts persist across every message in a conversation. They set the model's behavior once, so you don't need to repeat formatting instructions every time you send new content.

In the Anthropic Messages API, the system prompt is a top-level parameter in the API call. It is not a role inside the messages array.

Create the summarize.py script

Now you'll build the actual script that reads a file, sends its content to Claude with your system prompt, and prints the structured summary.

  • Create a new file called summarize.py in the same folder as your test_api.py file, then add this code:
import sys
import anthropic


def summarize_file(filepath):
    """Read a file and summarize it using Claude."""
    # Try to open and read the file
    try:
        with open(filepath, "r") as f:
            content = f.read()
    except FileNotFoundError:
        print(f"Error: File '{filepath}' not found.")
        sys.exit(1)

    # Check that the file isn't empty
    if not content.strip():
        print("Error: File is empty.")
        sys.exit(1)

What does this code do?

This is the first half of your summarize_file function. It handles reading the input file safely.

  • The try/except block catches the case where the file doesn't exist and prints a helpful error.
  • The if not content.strip() check prevents sending an empty document to the API.
  • Both error cases call sys.exit(1) to stop the script with a non-zero exit code, signaling failure.
  • Save summarize.py.
  • You won't see any output yet. The next chunk adds the API call that uses this file content.
  • Still inside the summarize_file function, add this code below the empty-file check:
    # Create the API client (reads ANTHROPIC_API_KEY from environment)
    client = anthropic.Anthropic()

    # Send the file content to Claude with our system prompt
    message = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=1024,
        system="You are a document summarizer. When given text, produce a structured summary with exactly three sections:\n\n## TL;DR\nOne sentence summarizing the entire document.\n\n## Key Points\nBullet list of the 3-5 most important points.\n\n## Action Items\nBullet list of any tasks, decisions, or follow-ups mentioned. If none exist, write 'No action items identified.'",
        messages=[
            {
                "role": "user",
                "content": f"Please summarize the following document:\n\n{content}",
            }
        ],
    )

    # Print the summary text from Claude's response
    print(message.content[0].text)

What does this code do?

This is where the AI magic happens. The code creates the API client and sends your document to Claude with structured instructions.

  • anthropic.Anthropic() creates the client. It automatically reads your ANTHROPIC_API_KEY from the environment.
  • The system parameter is your system prompt. It tells Claude to always output three sections: TL;DR, Key Points, and Action Items.
  • The messages array contains the user message with the actual file content injected via an f-string.
  • message.content[0].text extracts the text from Claude's response, just like you saw in the previous step.
  • Save summarize.py.
  • You won't see output yet. In the next step, you'll add a command-line interface to run this function on real files.

Why claude-haiku-4-5 instead of a larger model?

Claude Haiku 4.5 is the fastest and cheapest model in the Claude family. Summarization is a straightforward task that doesn't require complex reasoning, so Haiku handles it perfectly.

At $1 per million input tokens and $5 per million output tokens, running this project multiple times will cost well under $0.01.

✔️ Awesome, I've got everything!

Double check you've saved your file before moving on.

ⓧ I'd like to double check the full code

Here's the complete summarize.py file so far:

import sys
import anthropic


def summarize_file(filepath):
    """Read a file and summarize it using Claude."""
    try:
        with open(filepath, "r") as f:
            content = f.read()
    except FileNotFoundError:
        print(f"Error: File '{filepath}' not found.")
        sys.exit(1)

    if not content.strip():
        print("Error: File is empty.")
        sys.exit(1)

    client = anthropic.Anthropic()

    message = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=1024,
        system="You are a document summarizer. When given text, produce a structured summary with exactly three sections:\n\n## TL;DR\nOne sentence summarizing the entire document.\n\n## Key Points\nBullet list of the 3-5 most important points.\n\n## Action Items\nBullet list of any tasks, decisions, or follow-ups mentioned. If none exist, write 'No action items identified.'",
        messages=[
            {
                "role": "user",
                "content": f"Please summarize the following document:\n\n{content}",
            }
        ],
    )

    print(message.content[0].text)
Create your sample text file

Your summarizer needs something to summarize. You'll create a sample meeting notes file that has enough structure to produce interesting output across all three sections.

  • Create a new file called sample_notes.txt in the same folder as summarize.py, then paste the following content:
Team Meeting Notes - May 5, 2026

Attendees: Sarah, Mike, Lisa, James

Project Status Update:
Sarah reported that the new authentication system is 80% complete. The remaining work involves integrating with the legacy database, which has some undocumented API endpoints. She estimates two more days of work.

Mike presented the Q2 marketing results. Website traffic is up 34% compared to last quarter. The blog posts about AI tools are performing particularly well, with an average of 2,500 views per post. He recommends doubling the content output for Q3.

Budget Discussion:
Lisa flagged that we are currently 15% over budget for the engineering team due to unexpected cloud costs. She suggests we review our AWS usage and consider reserved instances to reduce costs by approximately 20%.

Action Items:
- Sarah to complete auth system integration by Friday
- Mike to draft Q3 content calendar by next Wednesday
- Lisa to schedule AWS cost review meeting with DevOps team
- James to send updated project timeline to stakeholders by end of day
- All team members to review the new PTO policy document shared via email

Why these meeting notes?

This sample has status updates, metrics, a budget discussion, and five action items. That variety will let you see how Claude handles each section of your system prompt differently.

  • Save sample_notes.txt.
  • Confirm both files exist by running:
ls
  • You should see summarize.py and sample_notes.txt listed alongside your existing test_api.py.

Don't see your files?

Make sure your terminal is in the same folder where you created the files. Run pwd to check your current directory.

If you created the files in VS Code, confirm they saved by checking for the dot indicator on the file tab. A dot means unsaved changes.

Help me find my project files

Your summarizer script and test file are ready. Next up, you'll add a command-line interface so you can run the tool directly from your terminal on any file.

Add Command-Line File Input

Your summarizer function can read a file and call Claude, but there is no way to run it from the terminal yet. Right now the script just defines a function without ever calling it.

Python's sys.argv list captures everything typed after python in the terminal command. You'll use it to grab the filename and pass it to your summarizer function.

In this step, get ready to:
  • Add a __main__ block that reads the filename from the command line.
  • Test error handling for missing arguments and non-existent files.
  • Run the complete summarizer on your sample meeting notes.
Add the command-line entry point

Python scripts need a __main__ block to know what code to run when you execute the file directly. This block checks the command-line arguments and calls your summarizer function.

  • In summarize.py, scroll to the very bottom of the file (after the summarize_file function) and add the following code:

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: python summarize.py <filename>")
        sys.exit(1)

    summarize_file(sys.argv[1])

What does this code do?

if __name__ == "__main__": runs the code inside only when you execute the script directly (not when importing it as a module).

sys.argv is a list of everything typed in the terminal. For python summarize.py notes.txt, sys.argv[0] is summarize.py and sys.argv[1] is notes.txt.

The len(sys.argv) != 2 check ensures the user typed exactly one filename. If they typed zero or more than one argument, the script prints a usage hint and exits.

  • Save summarize.py.

Seeing a syntax error?

Make sure the if __name__ block is at the top level of the file (no indentation), not inside the summarize_file function. Also check for two underscores on each side of __main__.

Help me fix a syntax error in my __main__ block

Test the error handling

Before running the summarizer on a real file, let's confirm the error handling catches bad input gracefully.

  • Test what happens when you provide no filename by running this command:
python summarize.py

You should see: Usage: python summarize.py <filename>.

  • Test what happens with a non-existent file by running:
python summarize.py fake_file.txt

You should see: Error: File 'fake_file.txt' not found..

Why test error cases first?

Testing the failures before the success confirms your script handles edge cases cleanly. The argument check you just added catches missing filenames. The FileNotFoundError handler and empty content check in summarize_file catch everything else.

Run the summarizer on your sample file

Now for the real test. Your summarizer is ready to process the meeting notes you created earlier.

  • Run the summarizer on your sample file by running this command:
python summarize.py sample_notes.txt

You should see a structured summary appear in your terminal with three sections: a TL;DR, Key Points, and Action Items.

What should the output look like?

Claude returns a structured summary based on your system prompt. The exact wording varies with each run, but the format stays consistent:

  • A TL;DR section with a single sentence summary.
  • A Key Points section with 3-5 bullets covering auth system progress, marketing results, and budget concerns.
  • An Action Items section listing the tasks assigned to each team member.

Seeing an authentication error?

If you see AuthenticationError, your ANTHROPIC_API_KEY environment variable is not set in this terminal session. Run echo $ANTHROPIC_API_KEY to check. If it prints nothing, re-export your key.

Help me fix an authentication error when calling the Claude API

✔️ Awesome, I've got everything!

Great. Double check you've saved summarize.py and your summarizer is producing structured output.

ⓧ I'd like to double check the full code

Here is the complete summarize.py file for comparison:

import sys
import anthropic


def summarize_file(filepath):
    """Read a file and summarize it using Claude."""
    try:
        with open(filepath, "r") as f:
            content = f.read()
    except FileNotFoundError:
        print(f"Error: File '{filepath}' not found.")
        sys.exit(1)

    if not content.strip():
        print("Error: File is empty.")
        sys.exit(1)

    client = anthropic.Anthropic()

    message = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=1024,
        system="You are a document summarizer. When given text, produce a structured summary with exactly three sections:\n\n## TL;DR\nOne sentence summarizing the entire document.\n\n## Key Points\nBullet list of the 3-5 most important points.\n\n## Action Items\nBullet list of any tasks, decisions, or follow-ups mentioned. If none exist, write 'No action items identified.'",
        messages=[
            {
                "role": "user",
                "content": f"Please summarize the following document:\n\n{content}",
            }
        ],
    )

    print(message.content[0].text)


if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: python summarize.py <filename>")
        sys.exit(1)

    summarize_file(sys.argv[1])

Your AI-powered document summarizer is complete. You now have a reusable command-line tool that turns any text file into a structured summary in seconds. Next, take on the Secret Mission to add multiple summary styles.

Secret mission

Multiple Summary Styles

Your summarizer works great, but every document is different. A quick Slack message needs a one-liner. A board report needs strategic recommendations. Can you add a --style flag that lets the user choose between brief, detailed, and executive summaries?

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally and uses the Anthropic API on a pay-per-use basis. There are no ongoing costs unless you actively run the script.

Decide whether to keep your resources as they are, pause by unsetting your API key, or delete everything entirely.

Resources you used:

  • summarize.py script (local file).
  • sample_notes.txt test file (local file).
  • anthropic Python package (installed via pip).
  • ANTHROPIC_API_KEY environment variable (set in your terminal session).

Keep everything running

No action needed. Choose this if you plan to keep using or extending your summarizer tool.

  • Your files and API key stay as they are.
  • You only pay when you run the script and make API calls.
  • You can reuse summarize.py on any text file going forward.

Pause - I'll come back to this later

Unset your API key to prevent accidental usage. Your files stay on disk for when you return.

  • Unset your API key for this terminal session by running:
unset ANTHROPIC_API_KEY
  • If you added the key to your shell profile (e.g. .zshrc or .bashrc), remove that line as well.
  • Your project files remain on your Desktop and are ready to use when you come back.

Delete - I don't want to use this again

Remove all project files and uninstall the package to start fresh.

  • Unset your API key by running:
unset ANTHROPIC_API_KEY
  • Delete your project files by running:
cd ~/Desktop
rm -rf summarize.py sample_notes.txt
  • Uninstall the Anthropic package by running:
pip uninstall anthropic -y
  • If you added the API key to your shell profile, remove that line manually.
  • Your Anthropic account and API key still exist. You can revoke the key in your Anthropic dashboard if you no longer need it.

Nice Work!

Nice Work!

You just built your first AI-powered command-line tool. Your summarizer can take any text file and turn it into a structured, actionable summary in seconds.

Here's what you learned:

  • Called the Anthropic Messages API from Python using the official SDK, including client setup and environment-based authentication.
  • Crafted a system prompt that produces consistent, structured output with TL;DR, Key Points, and Action Items.
  • Built a CLI tool that accepts file input, handles errors gracefully, and prints formatted summaries.
  • Added multiple summary styles with command-line flags using argparse.

Ready to quiz yourself?