Build a Bookmark Manager with Claude Code

Build a CLI bookmark manager using AI prompts — no manual coding required.

Introduction

30 Second Summary

Imagine building a fully functional application without typing a single line of code yourself. AI-powered coding agents can now take your ideas and turn them into working software through plain English conversation.

In this project, you will use Claude Code to build a command-line bookmark manager entirely through natural language prompts. You'll learn the core workflows that make AI-assisted development powerful, from prompting effectively to giving your AI persistent project memory.

What You'll Build

A Python CLI bookmark manager that saves, lists, searches, and deletes bookmarks stored in a local JSON file.

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

  • Claude Code installed and authenticated, ready to use in any project.
  • A working bookmark manager CLI built entirely through AI prompts without writing code by hand.
  • A CLAUDE.md file configured to give Claude Code persistent memory of your project's conventions.
  • Secret Mission: A custom Claude Code skill that automates your code review workflow.

Are there any prerequisites?

You need basic familiarity with using a terminal (navigating directories and running commands). No Python coding experience is required.

Claude Code requires a paid Anthropic subscription (Claude Pro at $20/month or Claude Max at $100-200/month). The free Claude.ai plan does not include Claude Code access.

Before We Start

Before We Start...

Install Claude Code and Set Up Your Environment

Before you can build anything with Claude Code, you need to get the right tools installed on your machine.

In this step, you will install Claude Code (your AI coding agent), Python 3 (the language your bookmark manager will be written in), and set up a project directory with Git for version control.

In this step, get ready to:
  • Install and verify Claude Code on your machine.
  • Install Python 3 and Git using Homebrew.
  • Create your project directory and authenticate Claude Code.
Install Claude Code

Claude Code is an AI coding agent that runs directly in your terminal. It can read your codebase, create and edit files, run commands, and commit code to Git.

What is Claude Code?

Claude Code is Anthropic's terminal-based AI assistant for developers. Unlike chat-based AI tools, Claude Code operates as an agent in your terminal. It understands your full project context, proposes changes, and waits for your approval before modifying files.

It requires a Claude Pro ($20/month), Max, Team, or Enterprise subscription. The free Claude.ai plan does not include Claude Code access.

  • Press Cmd+Space (macOS) to open Spotlight.
  • 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 installer script for Claude Code. The script installs the claude command-line tool on your system. It may ask for your Mac's password during installation.

  • Verify the installation by running:
claude --version

✔️ I see a version number

Claude Code is installed and ready to go. Continue to the next command below.

ⓧ Command not found

The installer may not have added Claude Code to your PATH yet.

  • Close your Terminal completely and reopen it.
  • Run claude --version again.
  • If it still fails, try running the install command again.

ⓧ I see a permission error

The installer needs permission to write to system directories.

  • Re-run the install command. When prompted, enter your Mac's password.
  • Run claude --version again to confirm it works.
  • Run a detailed health check by running:
claude doctor

You should see output confirming your system meets the requirements. This checks your macOS version, available RAM, and internet connectivity.

Seeing errors from claude doctor?

Make sure you are running macOS 13.0 or later. Claude Code requires an internet connection, at least 4 GB of RAM, and a Bash or Zsh shell.

Help me troubleshoot Claude Code installation issues on my Mac.

Install Python 3 and Git

Your bookmark manager will be a Python script. macOS does not come with Python 3 pre-installed, so you will use Homebrew (a package manager for macOS) to install it.

  • Check if Homebrew is already installed by running:
brew --version

✔️ I see a version number

Homebrew is already installed. Skip ahead to the Python install below.

ⓧ Command not found

You need to install Homebrew first.

  • Install Homebrew by running this command:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

What does this command do?

This runs Homebrew's official installer script. It will explain what it plans to do and ask you to confirm before making changes. You may need to enter your Mac's password.

  • Follow the on-screen prompts to complete the installation.
  • After installation completes, follow any instructions the installer prints about adding Homebrew to your PATH (it usually tells you to run two commands).
  • Close and reopen Terminal, then run brew --version to confirm it works.
  • Install Python 3 by running:
brew install python3

What does this command do?

This installs the latest stable version of Python 3 via Homebrew. It also installs pip3 (Python's package manager), though you will not need it for this project since your bookmark manager uses only Python's built-in libraries.

  • Verify Python is installed by running:
python3 --version

✔️ I see a version number

Python 3 is ready. Move on to checking Git below.

ⓧ Command not found

Homebrew may not have linked Python correctly.

  • Close and reopen Terminal.
  • Run python3 --version again.
  • If it still fails, run brew link python3 and try the version check once more.
  • Verify that Git is available by running:
git --version

✔️ I see a version number

Git is ready. Move on to creating your project directory.

ⓧ A dialog asks me to install developer tools

macOS is offering to install the Xcode Command Line Tools, which include Git.

  • Click Install in the dialog that appears.
  • Wait for the installation to finish (this may take a few minutes).
  • Run git --version again to confirm it works.

Python or Git install failing?

Make sure Homebrew is up to date by running brew update first. If the Python install hangs, check your internet connection.

Help me fix a Homebrew installation issue with Python 3 or Git on macOS.

Create the project directory and authenticate Claude Code

Now that your tools are installed, you will create a dedicated folder for your bookmark manager project and initialize it as a Git repository. Then you will authenticate Claude Code so it can connect to your Anthropic account.

  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir bookmark-manager
cd bookmark-manager
  • Initialize a Git repository inside your project folder by running:
git init

Why initialize Git now?

Claude Code integrates with Git to help you commit changes. By initializing a repository up front, Claude Code can track what has changed and write descriptive commit messages for you later in the project.

You should see a message confirming the repo was created (something like Initialized empty Git repository followed by the path).

  • Authenticate Claude Code by starting your first session:
claude

What happens when you run claude for the first time?

Since this is your first time running Claude Code, it will open your web browser and ask you to sign in to your Anthropic account. Follow the browser prompts to authorize access.

Once authenticated, you will be dropped into an interactive Claude Code session in your terminal. You will see the version number, the current model, and your working directory displayed above the prompt.

  • Follow the browser prompts to sign in with your Anthropic account (Claude Pro, Max, Team, or Enterprise).
  • Once you see the Claude Code prompt in your terminal, type exit to close the session for now.

You will return to Claude Code in the next step to start building your app.

Browser did not open or login failed?

Make sure you have an active Claude Pro, Max, Team, or Enterprise subscription. The free Claude.ai plan does not include Claude Code access.

If the browser did not open automatically, look for a URL printed in your terminal that you can copy and paste into your browser manually.

Help me troubleshoot Claude Code authentication.

  • Confirm your project directory is set up correctly by running:
ls -la

You should see a .git folder listed. This confirms Git is initialized in your bookmark-manager directory.

Your development environment is ready. Next up, you will start your first full Claude Code session and ask it to build something.

Start Your First Claude Code Session

Your environment is set up and ready to go. Now it's time to actually use Claude Code as your AI pair programmer.

In this step, you'll launch an interactive Claude Code session and learn how to communicate with it. You'll explore the interface, try basic prompts, and understand how Claude handles file changes before you let it build anything real.

In this step, get ready to:
  • Launch an interactive Claude Code session and explore the interface.
  • Try basic prompts to see how Claude Code reads and writes files.
  • Practice the permission model for approving or rejecting file changes.
Launch Claude Code in your project directory

Claude Code runs as an interactive session inside your terminal. When you start it, you get a prompt where you can type natural language requests and Claude will read, write, and modify files on your behalf.

  • Start a Claude Code interactive session by running this command in your terminal:
claude

What should I see?

You'll see the Claude Code prompt with the version number, current model, and your working directory displayed above it. The default model is Claude Sonnet 4.5.

You may also see a grayed-out prompt suggestion based on your project's Git history. Since this is a fresh repo, the suggestion might be generic.

  • Type the following at the Claude Code prompt to see all available commands:
/help

You should see a list of slash commands including /clear, /help, and others. These are built-in commands you can use anytime during a session.

Session not starting?

Make sure your terminal is inside the bookmark-manager directory. Run pwd to confirm.

If you see an authentication error, your login may have expired. Follow the browser login prompts that appear to re-authenticate.

Help me troubleshoot my Claude Code session

Explore Claude Code with basic prompts

Claude Code understands natural language. You can ask it questions about your project, request explanations, or ask it to create files. It reads your project directory to understand context before responding.

  • Type this prompt to see how Claude Code reads your project:
what files are in this directory?

Claude will scan your project folder and report back. Since you just initialized the repo, it should mention the .git directory and not much else.

  • Now ask Claude Code to create a file by typing this prompt:
create a simple hello world Python script

What happens next?

Claude Code will propose creating a Python file (likely hello.py) and show you the code it wants to write. It does NOT write the file immediately. Instead, it asks for your permission first.

This is the permission model in action. Claude Code always asks before modifying files on your system.

Approve or reject file changes

Claude Code's permission model keeps you in control. Every time Claude wants to create, edit, or delete a file, it shows you exactly what it plans to do and waits for your approval.

  • When Claude Code proposes creating the hello world script, accept the change by pressing Enter (or y) to approve.
  • After accepting, confirm the file was created by typing this prompt:
what files are in this directory now?

Claude should now report hello.py alongside the .git directory.

  • Practice cycling through permission modes by pressing Shift+Tab at the Claude Code prompt.

What are permission modes?

Pressing Shift+Tab cycles through different permission levels that control how much autonomy Claude Code has. In the default mode, Claude asks before every file change.

Plan mode is especially useful. In plan mode, Claude reads files and proposes a plan but makes no edits until you approve. You'll use plan mode later when adding features to your bookmark manager.

Claude didn't ask for permission?

If Claude wrote the file without asking, you may have accidentally switched to a more permissive mode. Press Shift+Tab to cycle back to the default permission mode.

Help me fix my Claude Code permission settings

You've got a feel for how Claude Code works. You can ask it questions, request changes, and stay in control of what actually gets written to disk. Next up, you'll put Claude Code to real work by building the complete bookmark manager application.

Build the Bookmark Manager

Your environment is set up and you've seen how Claude Code reads, writes, and explains code. Now it's time to put those skills to work on a real project.

In this step, you'll prompt Claude Code to build an entire bookmark manager CLI from scratch. You'll test it, fix any issues through conversation, and then add a new feature using plan mode to review changes before they hit disk.

In this step, get ready to:
  • Prompt Claude Code to generate a complete bookmark manager with add, list, search, and delete commands.
  • Test the app and have Claude Code fix any bugs.
  • Add an HTML export feature using plan mode to review changes before applying them.
Prompt Claude Code to build the full app

The power of Claude Code is that you can describe what you want in plain English and it builds the whole thing for you. A detailed prompt produces better results than a vague one.

  • In your Claude Code session, type this prompt and press Enter:
Build a bookmark manager CLI in Python. Requirements:
- Single file called bookmarks.py
- Commands: add (url, title, optional tags), list, search (by title/url/tags), delete (by index)
- Store bookmarks in a JSON file at ~/.bookmarks/bookmarks.json
- Use argparse for CLI argument parsing
- Use pathlib.Path for all file operations
- Include type hints on all functions
- Auto-create the storage directory and file if they don't exist
- Each bookmark should store: url, title, tags list, and created timestamp

Why be so specific in your prompt?

The more detail you give Claude Code, the closer the output matches what you want on the first try. Specifying the file name, storage location, library choices, and data shape means fewer rounds of back-and-forth to fix things later.

This is a core skill in agentic development. You're not writing code. You're writing specifications.

Claude Code will start creating bookmarks.py and explain its approach as it goes. It will ask for permission before writing the file to disk.

  • When Claude Code asks for permission to create bookmarks.py, approve the change by pressing y or Enter.

Watch Claude's explanation

As Claude Code writes the file, it explains what each section does. Read along to understand the structure it chose. You'll see functions for each command, a main entry point with argparse subparsers, and JSON storage logic.

Test the generated app

Code that looks correct might still have bugs at runtime. Testing the app immediately after generation catches issues while Claude Code still has the full context in memory.

  • Ask Claude Code to run the app for you by typing this prompt:
Run bookmarks.py with the "add" command to save https://nextwork.org with the title "NextWork" and tags "learning" and "projects"

Claude Code will run the command and show you the output. You should see a confirmation message that the bookmark was added.

  • Test the list command by typing:
Now run it with the "list" command to show all bookmarks

You should see the bookmark you just added, with its title, URL, and tags displayed.

  • Test search and delete too by typing:
Test the search command with "nextwork" and then test delete with index 1

What if something breaks?

If any command produces an error, Claude Code can see the traceback and fix it immediately. Just tell it what happened in plain language, like "the search command throws a KeyError" and it will update the code.

This iterative loop of testing and fixing through conversation is one of the key advantages of agentic development. You never have to debug manually.

Claude Code not running the commands?

If Claude Code describes what it would do instead of actually running the command, try rephrasing with "please execute" or "run this in the terminal". Make sure you approve any permission requests for running shell commands.

help me get Claude Code to run my Python script

Add HTML export using plan mode

Plan mode is a way to review what Claude Code intends to do before it makes any changes. This is valuable when you want to understand a proposed change or when you're working on code you care about getting right.

  • Press Shift+Tab to cycle the permission mode.
  • Keep pressing Shift+Tab until you see the mode indicator change to plan.

What is plan mode?

In plan mode, Claude Code reads your files and proposes a plan but makes no edits until you approve. Pressing Shift+Tab cycles through permission modes: default, acceptEdits, plan, and any other modes you have enabled.

This gives you a chance to read and understand what Claude Code will change before any code hits disk.

  • Now prompt Claude Code to add the export feature:
Add an "export" command that exports all bookmarks to an HTML file. It should generate a proper HTML document with a heading and an unordered list of linked bookmark titles. Include an --output flag that defaults to "bookmarks.html".

Instead of immediately writing code, Claude Code will describe its plan. You'll see what functions it intends to add, how it will modify the argument parser, and where the new code will go.

  • Read through the plan to make sure it matches what you want.
  • Approve the plan to let Claude Code apply the changes.
  • Test the new export command by typing:
Add a bookmark for https://docs.python.org with title "Python Docs" and then run the export command

You should see a confirmation that the bookmark was added, followed by a message that bookmarks were exported to bookmarks.html.

Plan mode not activating?

If pressing Shift+Tab doesn't seem to change anything, look for a mode indicator near the input prompt area. The mode name updates as you cycle through options.

help me switch to plan mode in Claude Code

✔️ Awesome, I've got everything!

Great. Double check that you've saved bookmarks.py and that it includes the export command alongside add, list, search, and delete.

ⓧ I'd like to double check the full code

Here's what your complete bookmarks.py should look like after Claude Code finishes building and adding the export feature. Your version may differ slightly in formatting or comments, but the core logic should match.

#!/usr/bin/env python3
"""A command-line bookmark manager that stores bookmarks in a local JSON file."""

import argparse
import json
import os
import sys
from datetime import datetime
from pathlib import Path


BOOKMARKS_DIR = Path.home() / ".bookmarks"
BOOKMARKS_FILE = BOOKMARKS_DIR / "bookmarks.json"


def ensure_storage() -> None:
    """Create the bookmarks directory and file if they don't exist."""
    BOOKMARKS_DIR.mkdir(parents=True, exist_ok=True)
    if not BOOKMARKS_FILE.exists():
        BOOKMARKS_FILE.write_text(json.dumps([], indent=2))


def load_bookmarks() -> list[dict]:
    """Load bookmarks from the JSON file."""
    ensure_storage()
    with open(BOOKMARKS_FILE, "r") as f:
        return json.load(f)


def save_bookmarks(bookmarks: list[dict]) -> None:
    """Save bookmarks to the JSON file."""
    ensure_storage()
    with open(BOOKMARKS_FILE, "w") as f:
        json.dump(bookmarks, f, indent=2)


def add_bookmark(url: str, title: str, tags: list[str] | None = None) -> None:
    """Add a new bookmark."""
    bookmarks = load_bookmarks()
    bookmark = {
        "url": url,
        "title": title,
        "tags": tags or [],
        "created": datetime.now().isoformat(),
    }
    bookmarks.append(bookmark)
    save_bookmarks(bookmarks)
    print(f"Added bookmark: {title} ({url})")


def list_bookmarks() -> None:
    """List all bookmarks."""
    bookmarks = load_bookmarks()
    if not bookmarks:
        print("No bookmarks saved yet.")
        return
    for i, bm in enumerate(bookmarks, 1):
        tags = f" [{', '.join(bm['tags'])}]" if bm.get("tags") else ""
        print(f"{i}. {bm['title']}{tags}")
        print(f"   {bm['url']}")


def search_bookmarks(query: str) -> None:
    """Search bookmarks by title, URL, or tags."""
    bookmarks = load_bookmarks()
    query_lower = query.lower()
    results = [
        bm
        for bm in bookmarks
        if query_lower in bm["title"].lower()
        or query_lower in bm["url"].lower()
        or any(query_lower in tag.lower() for tag in bm.get("tags", []))
    ]
    if not results:
        print(f"No bookmarks matching '{query}'.")
        return
    print(f"Found {len(results)} bookmark(s) matching '{query}':")
    for i, bm in enumerate(results, 1):
        tags = f" [{', '.join(bm['tags'])}]" if bm.get("tags") else ""
        print(f"{i}. {bm['title']}{tags}")
        print(f"   {bm['url']}")


def delete_bookmark(index: int) -> None:
    """Delete a bookmark by its index (1-based)."""
    bookmarks = load_bookmarks()
    if index < 1 or index > len(bookmarks):
        print(f"Invalid index: {index}. Use 'list' to see available bookmarks.")
        sys.exit(1)
    removed = bookmarks.pop(index - 1)
    save_bookmarks(bookmarks)
    print(f"Deleted bookmark: {removed['title']}")


def export_bookmarks_html(output_path: str) -> None:
    """Export bookmarks to an HTML file."""
    bookmarks = load_bookmarks()
    if not bookmarks:
        print("No bookmarks to export.")
        return
    html_lines = [
        "<!DOCTYPE html>",
        "<html><head><title>My Bookmarks</title></head>",
        "<body>",
        "<h1>My Bookmarks</h1>",
        "<ul>",
    ]
    for bm in bookmarks:
        tags = f" <em>[{', '.join(bm['tags'])}]</em>" if bm.get("tags") else ""
        html_lines.append(f'  <li><a href="{bm["url"]}">{bm["title"]}</a>{tags}</li>')
    html_lines.extend(["</ul>", "</body>", "</html>"])
    Path(output_path).write_text("\n".join(html_lines))
    print(f"Exported {len(bookmarks)} bookmark(s) to {output_path}")


def main() -> None:
    """Main entry point for the bookmark manager CLI."""
    parser = argparse.ArgumentParser(description="A command-line bookmark manager.")
    subparsers = parser.add_subparsers(dest="command", help="Available commands")

    # Add command
    add_parser = subparsers.add_parser("add", help="Add a new bookmark")
    add_parser.add_argument("url", help="The URL to bookmark")
    add_parser.add_argument("title", help="A title for the bookmark")
    add_parser.add_argument("--tags", nargs="*", default=[], help="Tags for the bookmark")

    # List command
    subparsers.add_parser("list", help="List all bookmarks")

    # Search command
    search_parser = subparsers.add_parser("search", help="Search bookmarks")
    search_parser.add_argument("query", help="Search term")

    # Delete command
    delete_parser = subparsers.add_parser("delete", help="Delete a bookmark by index")
    delete_parser.add_argument("index", type=int, help="Bookmark index (from list)")

    # Export command
    export_parser = subparsers.add_parser("export", help="Export bookmarks to HTML")
    export_parser.add_argument(
        "--output", default="bookmarks.html", help="Output file path"
    )

    args = parser.parse_args()

    if args.command == "add":
        add_bookmark(args.url, args.title, args.tags)
    elif args.command == "list":
        list_bookmarks()
    elif args.command == "search":
        search_bookmarks(args.query)
    elif args.command == "delete":
        delete_bookmark(args.index)
    elif args.command == "export":
        export_bookmarks_html(args.output)
    else:
        parser.print_help()


if __name__ == "__main__":
    main()

You've just built a fully functional CLI application without writing a single line of code yourself. Next up, you'll set up CLAUDE.md to give Claude Code persistent memory about your project's conventions.

Set Up CLAUDE.md for Project Memory

Your bookmark manager is built, tested, and ready to go. Now it's time to give Claude Code persistent memory of how your project works.

Every time you start a new Claude Code session, it begins fresh with no knowledge of your project's conventions. CLAUDE.md solves this by giving Claude a file it reads at the start of every session, loaded directly into its context window. The result: Claude follows your coding rules without you repeating them every time.

In this step, get ready to:
  • Generate a CLAUDE.md file using the /init command.
  • Edit CLAUDE.md to define your project's coding conventions.
  • Test that Claude Code follows your conventions in a new session.
Run /init to generate CLAUDE.md

The /init command tells Claude Code to scan your codebase and generate a starting CLAUDE.md file. It captures build commands, project structure, and conventions Claude observed in your code.

  • In your Claude Code session, type the following command and press Enter:
/init

Claude Code will analyze bookmarks.py and generate a CLAUDE.md file in your project directory. It displays the contents of the newly created file for your review.

What is CLAUDE.md?

CLAUDE.md is a special markdown file that Claude Code reads at the start of every session. It's loaded directly into Claude's context window, consuming tokens alongside your conversation.

Think of it as a brief for a new team member. Every time Claude Code starts up, it reads this file first so it knows how your project works, what commands to run, and what style rules to follow.

  • Confirm the file was created by checking for it in your project directory:
ls CLAUDE.md

You should see CLAUDE.md listed in the output.

Don't see CLAUDE.md?

Make sure you ran /init inside the Claude Code interactive session (the > prompt), not in a regular terminal window. The slash commands only work inside a Claude Code session.

help me troubleshoot why /init didn't create a CLAUDE.md file

Edit CLAUDE.md to add your conventions

The auto-generated CLAUDE.md is a starting point based on what Claude observed. Now you'll customize it with specific rules you want Claude Code to follow every time it writes code for this project.

  • Ask Claude Code to update CLAUDE.md with your project conventions by typing this prompt:
Update CLAUDE.md to have these sections: a Project Overview that says this is a command-line bookmark manager built with Python that stores bookmarks in a JSON file at ~/.bookmarks/bookmarks.json. A Build & Run section that shows the run command is python3 bookmarks.py <command> and notes no external dependencies are required (stdlib only). And a Conventions section with these rules: always include type hints in Python functions, use argparse for CLI argument parsing, store data in ~/.bookmarks/ directory, use pathlib.Path for file system operations, keep all code in a single file (bookmarks.py) for simplicity.

Claude Code will propose changes to CLAUDE.md. Review the proposed content and approve the file write.

Why add conventions manually?

The /init command observes what exists in your code, but it can't read your mind about future preferences. By spelling out conventions explicitly, you ensure Claude Code follows them even when adding brand new features that don't have existing patterns to reference.

Keep CLAUDE.md under 200 lines. Longer files consume more context tokens and reduce how well Claude follows the instructions.

  • Verify the file content by asking Claude Code:
Show me the contents of CLAUDE.md

You should see sections for Project Overview, Build & Run, and Conventions with your five rules listed.

✔️ Awesome, I've got everything!

Great. Your CLAUDE.md is ready to guide Claude Code in every future session.

ⓧ I'd like to double check the full code

Your CLAUDE.md should look like this:

# Bookmark Manager CLI

## Project Overview
A command-line bookmark manager built with Python. Stores bookmarks in a JSON file at ~/.bookmarks/bookmarks.json.

## Build & Run
- Run: `python3 bookmarks.py <command>`
- No external dependencies required (stdlib only)

## Conventions
- Always include type hints in Python functions
- Use argparse for CLI argument parsing
- Store data in ~/.bookmarks/ directory
- Use pathlib.Path for file system operations
- Keep all code in a single file (bookmarks.py) for simplicity

If your file doesn't match, ask Claude Code to replace the contents with the version above.

Test your conventions in a new session

CLAUDE.md is loaded at the start of every new session. To prove it works, you'll exit your current session and start a fresh one. Then you'll ask Claude Code to add a feature and watch whether it follows your conventions without being reminded.

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

Notice that Claude Code displays your working directory when it starts up. Behind the scenes, it has already loaded your CLAUDE.md into its context.

  • Ask Claude Code to add a small feature so you can observe convention adherence:
Add a "stats" command to the bookmark manager that shows how many total bookmarks are saved and how many unique tags exist
  • Review the code Claude proposes. Look for these signs that your conventions are being followed:

What if Claude didn't follow a convention?

If Claude's proposed code is missing type hints or uses a different approach than your conventions specify, it usually means the wording in CLAUDE.md could be more direct. Try rephrasing the rule to be more specific (e.g. "Every function signature must include return type annotations").

  • You can accept or reject the proposed feature. The important thing is that you've confirmed Claude Code reads and follows your CLAUDE.md conventions automatically.

Claude didn't seem to read CLAUDE.md?

Make sure you fully exited the previous session with exit and started a new one with claude. CLAUDE.md is only loaded at session start, not mid-session.

Also confirm that CLAUDE.md is saved in the same directory where you ran claude. Claude Code looks for it in the current working directory.

help me figure out why Claude Code isn't following my CLAUDE.md conventions

Your project now has persistent memory. Every future Claude Code session will start by reading your conventions and following them automatically. Next up, you'll explore advanced workflows like piping content for quick analysis, Git integration, and session management.

Use Advanced Workflows

Your project now has persistent memory thanks to CLAUDE.md. Every future Claude Code session will follow the conventions you defined without you repeating them.

Claude Code is more than an interactive chat. It has powerful workflows for quick one-off analysis, Git integration, and session management. In this step, you will use all three to round out your toolkit.

In this step, get ready to:
  • Pipe your code into Claude Code for a quick non-interactive review.
  • Use Git integration to commit your work with a descriptive message.
  • Resume and browse previous sessions.
Pipe content to Claude Code for quick analysis

Sometimes you want a fast answer without starting a full interactive session. Claude Code's non-interactive mode lets you send a prompt and get a response printed straight to your terminal.

  • Exit your current Claude Code session by typing:
exit
  • Pipe your bookmarks.py file into Claude Code for a code review by running this command:
cat bookmarks.py | claude -p "review this code for potential bugs and suggest improvements"

What does this command do?

  • cat bookmarks.py reads your file and sends its contents through the pipe.
  • claude -p runs Claude Code in non-interactive (print) mode. It processes the input, prints the response, and exits immediately.
  • The quoted string is your prompt. Claude Code receives both the file contents and the prompt together.

You should see Claude's analysis printed directly in your terminal. It will identify potential improvements or edge cases in your code.

Seeing a "command not found" error?

  • Make sure you exited the interactive Claude Code session first. You need to be at your regular shell prompt to run this command.
  • Confirm you are still inside the bookmark-manager directory where bookmarks.py lives.

Help me debug why piping content to Claude Code is not working

Commit your work with Git integration

Claude Code can interact with Git directly. Instead of running Git commands yourself, you can ask Claude Code to stage files, write a commit message, and execute the commit in one go.

  • Start a new Claude Code session by running:
claude
  • Ask Claude Code to commit your work by typing this prompt:
commit all changes with a descriptive commit message

What happens next?

Claude Code will stage all your project files (bookmarks.py and CLAUDE.md), compose a commit message describing your changes, and execute the git commit command.

Claude Code will ask for your permission before running each Git command. Approve the actions when prompted.

You should see a confirmation message showing the commit was created, along with the descriptive commit message Claude Code wrote for you.

Commit failed or not working?

  • Make sure you initialized a Git repository earlier (git init should have been run in a previous step). Run git status outside of Claude Code to check.
  • If Claude Code asks for your Git identity, provide a name and email when prompted.

Help me troubleshoot why Claude Code cannot commit my files with Git

Resume and manage Claude Code sessions

Claude Code saves every conversation locally. You can pick up exactly where you left off without re-explaining your project context.

  • Exit your current Claude Code session by typing exit.
  • Resume your most recent session by running:
claude -c

You should see your previous conversation restored, including the Git commit you just made.

  • Exit again with exit, then browse all your past sessions by running:
claude -r

What is the difference between -c and -r?

claude -c continues the most recent conversation in the current directory. It is the fastest way to pick up where you left off.

claude -r opens a session picker showing all your past sessions. Use it when you want to jump back to an older conversation or a session from a different directory.

You can exit the session picker by pressing Ctrl+C or selecting a session to continue.

No sessions showing up?

  • Make sure you ran at least one interactive Claude Code session in this directory before using claude -c or claude -r. The Git commit session from the previous substep counts.
  • Sessions are saved per directory. If you changed directories, Claude Code will not find sessions from bookmark-manager.

Help me find my previous Claude Code sessions

Secret mission

Create a Custom Skill

You've built a full CLI app and set up project memory. Now, take it further by creating a reusable Claude Code skill that packages your code review workflow into a single slash command. Every time you type /review, Claude will follow your exact review process automatically.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally, so there are no ongoing cloud costs. However, your Claude Pro subscription ($20/month) continues to bill unless you cancel or downgrade. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Resources you used:

  • bookmark-manager/ project directory on your Desktop.
  • ~/.bookmarks/ data directory (stores your saved bookmarks).
  • Claude Code (installed via native installer).
  • Python 3 (installed via Homebrew).
  • Git repository inside the project folder.

Keep everything running

No action needed. Choose this if you plan to keep building with Claude Code and want your bookmark manager ready to use.

  • Your project files stay on your Desktop in bookmark-manager/.
  • Claude Code remains installed and ready for any project.
  • Your bookmarks data persists in ~/.bookmarks/.
  • Python 3 and Git remain available system-wide.

Pause - I'll come back to this later

Free up disk space while keeping your project files intact. You can return anytime.

  • No running processes to stop. Everything in this project runs on-demand.
  • Your project folder, bookmarks data, and Claude Code all stay in place for next time.
  • To resume later, open Terminal, navigate to ~/Desktop/bookmark-manager, and run claude to start a new session.

Delete - I don't want to use this again

Remove all project resources and start fresh. This deletes your project files, bookmark data, and Claude Code installation.

  • Delete the project folder by running:
rm -rf ~/Desktop/bookmark-manager
  • Delete your saved bookmarks data by running:
rm -rf ~/.bookmarks
  • Uninstall Claude Code by removing its binary and data:
rm -f ~/.local/bin/claude
rm -rf ~/.local/share/claude
  • Remove Claude Code configuration files:
rm -rf ~/.claude
rm ~/.claude.json
  • Uninstall Python 3 from Homebrew by running:
brew uninstall python@3

What about Git?

Git is a general-purpose tool you will likely use in many future projects. There is no need to uninstall it.

Nice Work!

Nice Work!

You just built an entire CLI application without writing a single line of code by hand. That is the power of agentic development with Claude Code.

You've learned how to:

  • Built a functional bookmark manager CLI entirely through natural language prompts, proving you can go from idea to working software with an AI coding agent.
  • Configured CLAUDE.md project memory so Claude Code remembers your conventions across sessions, and used plan mode to review AI-proposed changes before they hit disk.
  • Used advanced workflows including piping content for quick analysis, Git integration for descriptive commits, and session management to continue conversations across work sessions.
  • Created a custom skill that packages a repeatable code review workflow into a simple slash command.

Ready to quiz yourself?