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?