Build a CLI App Using Claude Code

Build a Python bookmark manager using Claude Code's agentic workflows.

Introduction

30 Second Summary

Imagine building an entire app by describing what you want in plain English, then watching an AI write, run, and test the code for you. That's the new workflow that agentic coding tools unlock.

In this project, you will use Claude Code to build a Python command-line bookmark manager entirely through natural-language prompts. Along the way, you'll learn the core workflows that make Claude Code powerful: plan mode, project memory, and checkpoints.

What You'll Build

You'll type a single description of the app you want, hit Enter, and watch Claude Code autonomously plan, write, and verify a working CLI tool you can run immediately.

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

  • A working bookmark manager you can run from your terminal, built entirely by giving Claude Code a single natural-language description of what you want.
  • Hands-on experience with plan mode and checkpoints to review Claude Code's strategy before it edits your files, and safely rewind when it goes in a direction you don't want.
  • A CLAUDE.md file that gives Claude Code persistent memory of your project's conventions, so every new session picks up exactly where you left off.
  • Secret Mission: Use Claude Code's non-interactive mode to pipe it into a script that auto-generates documentation for your project.

Are there any prerequisites?

You'll need a Claude Pro or Max plan (Claude Code is included at no extra cost) and Python 3 installed on your Mac. Step 1 walks you through installing Claude Code itself.

Before We Start

Before we dive in, let's lock in what you're about to build and why it matters.

You're going to build a Python CLI bookmark manager, but the app itself is just the vehicle. The real goal is learning the Claude Code workflows that let you go from a natural-language description to working software in minutes.

Install Claude Code and Start Your First Session

Claude Code is a terminal-based AI coding assistant that reads your files, writes code, and runs commands autonomously. Before you can use it to build your bookmark manager, you need it installed and connected to your Claude Pro/Max account.

In this step, you'll install the Claude Code CLI, authenticate it with your plan, and get comfortable with the basic commands you'll use throughout this project.

In this step, get ready to:
  • Install the Claude Code CLI on your Mac.
  • Authenticate with your Claude Pro/Max credentials.
  • Learn the essential keyboard shortcuts and commands.
Install Claude Code

Claude Code is a CLI tool that runs directly in your terminal. You'll install it using an official install script from Anthropic.

  • Press Cmd+Space to open Spotlight search.
  • Type Terminal and press Enter to open it.
  • Install Claude Code by running this command:
curl -fsSL https://claude.ai/install.sh | bash

What does this command do?

This downloads and runs Anthropic's official install script. It places the claude binary on your system so you can use it from any terminal window.

Prefer Homebrew?

If you already use Homebrew on your Mac, you can install Claude Code with:

brew install --cask claude-code

Both methods give you the same CLI. Pick whichever you prefer.

Before you run the version check below, what do you think you'll see if the install worked?

  • Verify the installation by running:
claude --version

You should see a version number printed, like 2.x.x. This confirms Claude Code is installed and ready.

✔️ I see a version number

Claude Code is installed and ready. Move on to the next substep.

ⓧ Command not found

Your terminal cannot find the claude command. Try these fixes:

  • Close your terminal completely and open a new window. The install script updated your PATH, but the current session may not have picked it up.
  • Run the install command again and check for any error messages in the output.
  • If you used Homebrew, run brew list --cask to confirm claude-code appears in the list.

After trying these fixes, run claude --version again in your new terminal window.

Authenticate and start a session

Now that Claude Code is installed, you need to connect it to your Claude Pro/Max plan. Authentication happens automatically the first time you start a session.

  • Create your project directory and move into it by running:
mkdir ~/bookmark-cli && cd ~/bookmark-cli

What does this command do?

This creates a new folder called bookmark-cli in your home directory and moves your terminal into it. This is where your entire bookmark manager project will live.

  • Start Claude Code by running:
claude

What happens on first run?

Claude Code will open your default browser and ask you to log in with your Anthropic account. This is how it connects to your Claude Pro/Max plan.

After you approve access in the browser, switch back to your terminal. You'll see the Claude Code prompt with the model name and your working directory displayed above it.

  • Complete the login in your browser when prompted.
  • Switch back to your terminal after approving access.

You should see the Claude Code interface with a > input prompt, the model name, and your ~/bookmark-cli working directory displayed above it.

  • Type /help and press Enter to see the list of available commands.
  • Type /exit and press Enter to leave the session for now.

Browser didn't open for login?

If you have an ANTHROPIC_API_KEY environment variable set, Claude Code skips the browser login and uses that key instead. If you want to use your Pro/Max plan's included usage, unset the variable by running unset ANTHROPIC_API_KEY in your terminal, then start claude again.

help me troubleshoot Claude Code authentication

Explore the essential commands

Claude Code has a small set of keyboard shortcuts that you'll use constantly. Knowing these before you build anything will save you time.

  • Start Claude Code again by running:
claude
  • Try typing a short message but press Ctrl+J instead of Enter. This inserts a newline without submitting, letting you write multi-line prompts.
  • Press Enter to submit your message when you're ready.

Key interactions to remember

  • Enter submits your message to Claude.
  • Ctrl+J inserts a newline without submitting.
  • Shift+Tab cycles permission modes (default, acceptEdits, plan).
  • /help shows all available commands.
  • /exit or Ctrl+D twice exits the session.
  • Type /exit and press Enter to leave Claude Code.

You're back in your regular terminal prompt, inside the ~/bookmark-cli directory. Claude Code is installed, authenticated, and you know the essential commands.

Your environment is ready. Next up, you'll give Claude Code a real task and watch it autonomously build an entire Python app from a single prompt.

Build Your App with a Single Prompt

Your environment is set up and Claude Code is ready to go. Now it's time to see what makes Claude Code different from a regular code editor.

Instead of writing code line by line, you'll describe what you want in plain English. Claude Code reads your prompt, plans an approach, writes the files, and can even run the code to verify it works. This is the agentic loop in action.

In this step, get ready to:
  • Give Claude Code a natural-language prompt describing your bookmark manager.
  • Test the CLI app that Claude Code builds for you.
Give Claude Code your first real task

Your ~/bookmark-cli directory is empty right now. You'll fill it with a working app by giving Claude Code a single prompt describing what you want.

  • Start Claude Code in your terminal by running:
claude

You'll see the Claude Code prompt appear with the model name and your working directory displayed above it.

  • Type the following prompt into Claude Code. You can copy and paste it directly into the session (pasting preserves newlines):
Build a Python CLI bookmark manager called bookmark.py. It should support these commands:
- python3 bookmark.py add <url> <title> - adds a bookmark
- python3 bookmark.py list - shows all bookmarks
- python3 bookmark.py search <query> - searches bookmarks by title or URL
- python3 bookmark.py delete <id> - deletes a bookmark by its ID

Store bookmarks in a bookmarks.json file. Use argparse for CLI parsing. Keep it simple - one file is fine.
  • Press Enter to submit the prompt.

Watch Claude Code work. It will plan its approach, then start writing code to your bookmark.py file.

  • Claude Code asks for permission before writing files (you're in default permission mode). Approve each action by pressing y when prompted.

What's happening in the agentic loop?

Claude Code is doing more than autocomplete. It reads your prompt, decides what files to create, writes the full implementation, and may even run the code to verify it works.

Each time it wants to create or edit a file, it pauses and asks you to approve. This is the default permission mode at work. You stay in control of what actually lands on disk.

Claude Code isn't producing output?

If Claude Code seems stuck, check that you submitted the prompt with Enter. If you accidentally pressed Ctrl+J, that inserts a newline without sending. Press Enter to submit.

help me debug why Claude Code isn't responding to my prompt

Test the app Claude built

Claude Code has written your app. Now you'll run it yourself to confirm everything works. You need a separate terminal window since Claude Code is still running in your current one.

  • Open a new terminal tab by pressing Cmd+T (macOS).
  • Navigate to your project folder by running:
cd ~/bookmark-cli

Before you run any commands, what do you think you'll see if you list bookmarks in a brand-new app with no data?

  • Test the list command by running:
python3 bookmark.py list

You should see output like "No bookmarks found" or an empty list. This proves your CLI app exists and runs successfully.

  • Add your first bookmark by running:
python3 bookmark.py add "https://docs.anthropic.com" "Claude Code Docs"
  • Add a second bookmark by running:
python3 bookmark.py add "https://github.com" "GitHub"
  • List all bookmarks to see your entries by running:
python3 bookmark.py list

You should see both bookmarks displayed with their IDs, URLs, and titles.

  • Search for a bookmark by running:
python3 bookmark.py search "claude"

You should see only the "Claude Code Docs" bookmark returned in the search results.

What just happened?

You described an app in plain English and Claude Code built the entire thing. It chose argparse for CLI parsing, set up JSON file storage, and implemented all four commands. That's one prompt to a working tool.

Seeing an error when you run the commands?

Switch back to your Claude Code tab and paste the error message directly into the session. Claude Code will read the traceback, trace the issue, and fix it. This is part of the normal agentic workflow.

help me fix an error when running bookmark.py

You have a working CLI tool built entirely from a single natural-language prompt. Next up, you'll learn plan mode to review Claude Code's strategy before it changes your files.

Use Plan Mode to Review Before Editing

Your bookmark manager works. You gave Claude Code a prompt, it wrote the code, and you approved each file change one by one.

That per-change approval works fine for small tasks. For bigger features, you want to see the full strategy before any code touches disk. Plan mode lets you review Claude Code's entire approach before it edits a single file.

In this step, get ready to:
  • Switch Claude Code into plan mode.
  • Review a proposed plan for a new feature before any files are edited.
  • Approve the plan and test the result.
Switch to plan mode

In default mode, Claude Code asks for permission before each individual file write. Plan mode takes a different approach. It makes Claude Code show you the full plan for your request without touching any files until you give the green light.

  • Start Claude Code in plan mode by running this command:
claude --permission-mode plan

What does this flag do?

The --permission-mode plan flag starts Claude Code in a mode where it reads your files and proposes changes, but makes no edits until you explicitly approve the full plan.

If you're already inside a Claude Code session, you can also press Shift+Tab to cycle through permission modes: default, acceptEdits, plan. Stop when the status bar shows "plan mode on".

You should see the Claude Code prompt appear with the status bar indicating plan mode is active.

Don't see plan mode in the status bar?

Make sure you typed the flag exactly as --permission-mode plan (two dashes, no spaces around the equals sign alternative). If Claude Code launched in default mode, press Shift+Tab twice to cycle from default through acceptEdits to plan.

Still stuck? Help me get Claude Code into plan mode

Ask for a feature and review the plan

Now you'll ask Claude Code to add a tags feature to your bookmark manager. In plan mode, Claude will read your existing code and propose a strategy. It will not write or edit any files yet.

  • Type this prompt into Claude Code and press Enter:
Add a "tags" feature. Users should be able to add tags when creating a bookmark (python3 bookmark.py add <url> <title> --tags tag1,tag2) and filter bookmarks by tag (python3 bookmark.py list --tag <tag>).

Claude Code reads your bookmark.py file, then responds with a plan describing what it intends to change. No files are modified at this point.

What should I see in the plan?

Claude Code's plan typically describes which files it will modify, what new arguments it will add to argparse, and how it will store and filter tags. The details depend on your specific code, but you should see a clear strategy covering both the --tags option on add and the --tag filter on list.

This is your chance to catch issues before they become code. Does the approach make sense? Would you change anything?

Approve or redirect the plan

You have two choices. If the plan looks good, approve it and Claude Code executes the changes. If something feels off, tell Claude what to adjust and it will revise the plan before touching any files.

  • Review the plan Claude proposed. If it makes sense, approve it so Claude Code can execute the changes.
  • If you want something different, type your feedback (e.g., "store tags as a list, not a comma-separated string") and Claude will revise the plan first.

Once you approve, watch Claude Code edit your files. It updates bookmark.py to support the new tags feature.

Why is this better than default mode?

In default mode, Claude asks permission for each individual file write. That's fine for small changes. For a multi-part feature like tags, plan mode lets you evaluate the whole strategy at once. You can redirect before any code is written, saving time on undo-and-redo cycles.

Before you test the tags feature, what do you expect to see when you add a bookmark with tags and then filter by one of those tags?

  • Test the tags feature by running these commands inside Claude Code (prefix each with ! to run shell commands directly):
! python3 bookmark.py add "https://python.org" "Python" --tags python,programming
! python3 bookmark.py list --tag python

The first command adds a bookmark with two tags. The second command filters your bookmarks to show only those tagged with "python". You should see the Python bookmark appear in the filtered results.

Seeing an error when testing?

If the command fails, paste the error message directly into Claude Code. It will read the traceback, identify the issue, and fix it. This is the normal workflow. Claude Code is your debugging partner.

If Claude Code's fix still doesn't work after a couple of attempts, check that you approved all the planned changes before testing.

Help me debug my tags feature

Your bookmark manager now supports tags, and you've experienced the difference between approving changes one at a time versus reviewing the full strategy upfront. Next up, you'll give Claude Code long-term memory so it remembers your project conventions across sessions.

Create a CLAUDE.md for Project Memory

Your bookmark manager works and you've used plan mode to control Claude Code's approach to changes. But there's a gap in the workflow. Every time you start a new Claude Code session, it starts completely fresh with no memory of your preferences or project standards.

CLAUDE.md solves this. It's a markdown file that Claude Code reads at the start of every session, giving it persistent context about your project's rules, conventions, and architecture. You'll never have to re-explain your coding standards again.

In this step, get ready to:
  • Generate a starter CLAUDE.md using the /init command.
  • Customize CLAUDE.md with your project's specific conventions.
  • Verify that a fresh session picks up your rules automatically.
Generate a starter CLAUDE.md

Claude Code has a built-in command that analyzes your project structure and generates a starter CLAUDE.md file. This gives you a foundation to build on rather than starting from a blank file.

  • Start a Claude Code session in your bookmark-cli directory by running:
claude
  • Once you see the Claude Code prompt, generate your starter CLAUDE.md by typing:
/init

Claude Code scans your project files and generates a CLAUDE.md in the project root. You'll see it draft sections covering your project overview, commands, and code structure.

What does /init do?

The /init command reads your existing code, config files, and project structure. It uses what it finds to generate a CLAUDE.md tailored to your specific project.

The generated file is a starting point. It captures what Claude Code can infer, but it won't know your personal coding preferences yet. That's what the next substep fixes.

Don't see CLAUDE.md created?

Make sure you're inside a Claude Code session (you should see the Claude Code prompt, not your regular terminal). The /init command only works inside an active session.

If Claude Code asks for permission to write the file, approve it. Help me troubleshoot why /init isn't creating my CLAUDE.md file.

Ask Claude to refine CLAUDE.md with your rules

The starter CLAUDE.md captures your project's structure, but it doesn't know your personal coding standards. You can tell Claude Code exactly what conventions to encode.

  • Type this prompt into Claude Code to update CLAUDE.md with your specific rules:
Update CLAUDE.md with these rules:
- Use argparse for all CLI parsing
- Store all data in bookmarks.json in the project root
- Use type hints on all functions
- Keep everything in a single bookmark.py file
- Run tests with: python3 -m pytest test_bookmark.py
- Error messages should be user-friendly, not tracebacks
  • Approve when Claude Code asks to write to CLAUDE.md.

Why these specific rules?

Each rule solves a real problem. "Use argparse" prevents Claude from switching to click or sys.argv parsing. "Keep everything in bookmark.py" stops Claude from refactoring into multiple files when you didn't ask for it.

"User-friendly error messages" means Claude will wrap exceptions in helpful output instead of letting raw tracebacks confuse users. These rules persist across every future session.

  • Verify the update worked by asking Claude Code:
Show me what's in CLAUDE.md now

Claude Code should display the updated file with all six of your rules included.

Rules missing from CLAUDE.md?

If some rules didn't make it in, simply tell Claude Code which ones are missing and ask it to add them. Claude Code can edit CLAUDE.md just like any other file in your project.

Help me make sure all my rules are in CLAUDE.md.

Verify project memory works

The real test of CLAUDE.md is whether a brand new session picks up your rules without you repeating them. Time to prove it works.

  • Exit your current Claude Code session by typing:
/exit
  • Start a fresh Claude Code session by running:
claude

Before you ask your next question, think about this: what do you expect Claude Code to know about your project right now, without you telling it anything?

  • Ask Claude Code about your project conventions by typing:
What are the project conventions?

Claude Code references your CLAUDE.md rules in its response. It should mention argparse, bookmarks.json, type hints, the single-file structure, and user-friendly error messages. You didn't have to re-explain anything.

What is project memory?

CLAUDE.md is a markdown file Claude Code reads at the start of every conversation. It gives Claude persistent context about coding standards, architecture decisions, preferred libraries, and review checklists.

You can update it anytime. As your project evolves, add new conventions or remove outdated ones. Claude Code always reads the latest version.

Claude Code not referencing your rules?

Make sure CLAUDE.md is in the root of your bookmark-cli folder, not inside a subfolder. You can check by running ls ~/bookmark-cli/CLAUDE.md in a separate terminal window.

Also confirm you started Claude Code from inside the bookmark-cli directory. Claude Code reads CLAUDE.md from the working directory where the session starts.

Help me figure out why Claude Code isn't reading my CLAUDE.md file.

Your project now has persistent memory. Every future Claude Code session in this directory starts with full knowledge of your standards. Next up, you'll learn how to safely undo changes when Claude goes in a direction you don't want.

Use Checkpoints to Safely Undo Changes

Your CLAUDE.md gives Claude Code memory across sessions. But what happens when Claude Code makes changes you don't like?

When you ask Claude Code to make ambitious changes, sometimes the result isn't what you wanted. Checkpoints solve this by automatically saving your code state before each change, letting you rewind instantly. This gives you confidence to experiment freely.

In this step, get ready to:
  • Initialize a git repository so checkpoints pair with version control.
  • Ask Claude Code to make a big refactor and watch checkpoints save your state.
  • Rewind to a previous checkpoint and confirm your files are restored.
Initialize git for checkpoint tracking

Checkpoints work best alongside version control. A git commit gives you an extra safety net and lets you verify rewinds with git diff.

  • If you're still inside a Claude Code session, type /exit to return to your terminal.
  • Initialize a git repository and make your first commit by running these commands:
git init
git add .
git commit -m "Initial bookmark CLI"

What do these commands do?

  • git init creates a new Git repository in your project folder.
  • git add . stages all your current files for the commit.
  • git commit -m saves a snapshot with a message. This snapshot is your safe "known good" state.
  • Confirm your commit exists by running:
git log --oneline

You should see one line with your commit message Initial bookmark CLI.

Ask Claude Code instead

You can also do this from inside Claude Code by typing: "initialize a git repo and commit everything." Claude Code runs the same commands for you.

Ask Claude Code for an ambitious change

Now you'll deliberately ask Claude Code for a change you plan to undo. This simulates a real scenario where an AI-driven refactor goes in a direction you don't want.

  • Start Claude Code by running:
claude
  • Once inside the session, type this prompt to request a major refactor:
Refactor bookmark.py to use a SQLite database instead of JSON. Migrate the storage layer.

Watch Claude Code work. It will read your existing code, plan the migration, and start rewriting bookmark.py to use SQLite instead of your JSON file.

  • Approve the file edits when Claude Code asks for permission. Let it complete the refactor.

What's happening behind the scenes?

Every prompt you send creates a checkpoint. Claude Code automatically snapshots your files before each change it makes. Even as it rewrites bookmark.py to use SQLite, your original JSON-based version is safely stored in a checkpoint.

Checkpoints apply to Claude's file edits only. They don't capture changes made through bash commands or external processes.

Once Claude finishes, your bookmark.py now uses SQLite. You can verify this by glancing at the imports or asking Claude to summarize what it changed.

Rewind to the previous state

You've decided you actually prefer the JSON approach. Time to rewind.

  • Open the rewind menu by typing /rewind in the Claude Code prompt.

Keyboard shortcut for rewind

You can also press Esc twice quickly when the input is empty to open the rewind menu.

The rewind menu lists each prompt you sent during the session. You need to select the point before the SQLite refactor.

  • Select the checkpoint that corresponds to before you sent the SQLite refactor prompt.
  • Choose Restore code and conversation from the action list.

What are the rewind options?

  • Restore code and conversation reverts both your files and the chat history to that checkpoint.
  • Restore conversation rewinds only the chat while keeping your current code.
  • Restore code reverts file changes while keeping the full conversation.
  • Never mind returns you to the session without changes.

Before you verify, what do you think bookmark.py looks like now? Do you expect to see import sqlite3 or import json at the top?

  • Exit Claude Code by typing /exit.
  • Verify your files reverted by running:
git diff

You should see no output from git diff. This confirms your files match the committed JSON-based version exactly.

  • Double-check by looking at the top of bookmark.py:
head -5 bookmark.py

You should see import json (not import sqlite3). Your project is back to its JSON-based state.

Still seeing SQLite code?

  • Make sure you selected the checkpoint from before the SQLite prompt, not after it.
  • Confirm you chose Restore code and conversation (not just Restore conversation). The conversation-only option leaves your files unchanged.
  • If the rewind didn't work as expected, you can always fall back to git: run git checkout -- . to restore all files to your last commit.

help me rewind to a previous checkpoint in Claude Code

Why checkpoints are not a replacement for git

Checkpoints only track changes made through Claude's file editing tools. Changes made through bash commands or external processes are not captured. Always pair checkpoints with version control for complete coverage.

You now have a safety net for any experiment. With checkpoints and /rewind, you can ask Claude Code for any ambitious change knowing you can always get back to a working state. Next up, you'll take Claude Code beyond interactive sessions and into automation.

Secret mission

Automate with Non-Interactive Mode

So far you've used Claude Code interactively, typing prompts and reviewing responses in a live session. But Claude Code can also run as a headless Unix-style tool. In this mission, you'll pipe your source code into Claude Code to auto-generate a README, then wrap it in a reusable script.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally, so there are no ongoing costs. Decide whether to keep your files for future Claude Code sessions or remove them entirely.

Resources you used:

  • ~/bookmark-cli directory with your Python project files (bookmark.py, CLAUDE.md, bookmarks.json, generate-docs.sh, README.md, .git).
  • ~/.claude directory storing Claude Code session data locally.

Keep everything running

No action needed. Choose this if you want to keep building with Claude Code on this project.

  • Your ~/bookmark-cli directory stays on disk, ready for more Claude Code sessions.
  • Claude Code is included in your Pro/Max plan with no separate charges.
  • Session data in ~/.claude persists for conversation history and future sessions.

Pause - I'll come back to this later

There is nothing to pause here. Claude Code runs locally and is included in your Pro/Max plan with no ongoing charges.

  • Your project files remain on disk without consuming any resources.
  • Claude Code does not run in the background. It only activates when you start a session.
  • Come back any time by running cd ~/bookmark-cli && claude to pick up where you left off.

Delete - I don't want to use this again

Remove all project files and session data to start fresh.

  • Delete your project directory by running:
rm -rf ~/bookmark-cli
  • Remove Claude Code session data for this project by running:
rm -rf ~/.claude/projects/*bookmark-cli*

What about Claude Code itself?

These commands remove your project and its session history. Claude Code itself stays installed on your machine for future projects. If you want to fully uninstall Claude Code later, run:

brew uninstall --cask claude-code

This only works if you originally installed via Homebrew. If you used the curl install script, remove the binary manually from your PATH.

Nice Work!

Nice Work!

You just built a fully working Python CLI bookmark manager without writing a single line of code yourself. Every file in your project was authored by Claude Code, guided by your natural-language prompts.

You've learned how to:

  • Build a multi-command Python CLI app entirely through Claude Code's agentic loop, from a single natural-language prompt to a working tool with add, list, search, and delete commands.
  • Control Claude Code's behavior using plan mode to review strategy before edits, CLAUDE.md for persistent project memory, and checkpoints to safely rewind changes you don't want.
  • Use permission modes to decide how much autonomy Claude Code gets, from reviewing every file write to letting it execute a full plan hands-free.
  • Secret Mission: Automated README generation using non-interactive mode (claude -p) as a Unix-style tool, piping source code in and getting structured documentation out.

Ready to quiz yourself?