Module 8: Capstone project: Your first project with Claude Code
Explore and Plan: Design Before You Build
Explore and Plan: Design Before You Build
Project goal
Build a working CLI tool using the complete Claude Code workflow. In this capsule you complete Phase 2: Explore + Plan — you'll use Claude Code to analyze your setup and design the implementation before writing any code.
What you built in previous modules
- Capsule 02 (this module): You created the project with CLAUDE.md, 2 skills, 2 hooks, and the base entry point
- Module 04: You learned the Explore → Plan → Code cycle and when to use each mode
What you'll add in this module
By the end of this capsule you'll have:
- A complete analysis of your project's state (Explore)
- A detailed implementation plan for your CLI (Plan)
- A plan reviewed and iterated with feedback (multi-turn)
- An approved plan, ready to implement in the next capsule
You won't write any functional code yet. This capsule is 100% analysis and design.
Step-by-step walkthrough
Step 1: Open Claude Code in the project
Go to your project directory and open Claude Code:
cd my-cli-project
claude
Claude reads your CLAUDE.md automatically when the session starts. You don't need to mention it — it already has your project's context.
You should see something like:
╭──────────────────────────────────────────────────────╮
│ Claude Code │
│ │
│ /help for help │
│ │
│ Loaded CLAUDE.md (project context) │
╰──────────────────────────────────────────────────────╯
The "Loaded CLAUDE.md" message confirms Claude has your context. If you don't see it, check that CLAUDE.md is at the root of the project.
Step 2: Explore — Analyze the project's state
The Explore phase is read-only analysis. You ask Claude to investigate the project's current state without making any changes.
The Explore prompt
Type this into Claude Code:
Explore this project and give me a report on its current state. I want to know:
1. What files exist and what's the structure?
2. Is CLAUDE.md complete and consistent?
3. Are the skills created correctly?
4. Are the hooks configured properly?
5. Does the CLI entry point work?
6. Are the dependencies installed?
Don't make any changes, just analyze.
What to expect from Claude
Claude will:
- Read the directory structure — verify that the files exist where they should
- Read CLAUDE.md — confirm it has the 6 sections and is consistent
- Read the skills — verify that
.claude/skills/create-command/SKILL.mdand.claude/skills/add-tests/SKILL.mdexist and have valid content - Read settings.json — confirm the hooks are configured
- Check the entry point — read
cli.pyorindex.tsand confirm the structure is correct - Check dependencies — read
pyproject.tomlorpackage.json
Typical Explore output
## Project report
### Structure
The project has the expected structure:
- CLAUDE.md ✅ (56 lines, well structured)
- .claude/skills/create-command/SKILL.md ✅
- .claude/skills/add-tests/SKILL.md ✅
- .claude/settings.json ✅ (2 hooks configured)
- src/cli.py ✅ (entry point with Click)
- tests/ ✅ (empty, ready for tests)
### CLAUDE.md
All 6 sections are present:
1. Description ✅
2. Stack ✅
3. Structure ✅
4. Conventions ✅
5. Commands ✅
6. Rules ✅
Note: The structure section mentions 3 commands
(command_one, command_two, command_three) but the files
don't exist yet. That's correct — they'll be created in the
implementation phase.
### Skills
- /create-command: Complete template, clear instructions,
naming rules ✅
- /add-tests: Template with pytest/CliRunner, minimum 3 tests ✅
### Hooks
- PostToolUse (Write → ruff/eslint): ✅
- PreToolUse (Execute → git commit → tests): ✅
### Entry point
- src/cli.py exists with a Click group and version_option ✅
- CLI runs: `python -m src.cli --help` works ✅
### Dependencies
- click 8.1.7 installed ✅
- pytest 8.0.0 installed ✅
- ruff 0.4.0 installed ✅
### Overall state: Ready for implementation
The project is configured correctly. The next phase is
planning the CLI's 3 commands.
If Claude finds problems
If the report shows errors, fix them before continuing. Common problems:
| Problem | Fix |
|---|---|
| CLAUDE.md is missing a section | Add it by hand, or ask Claude to do it |
| A skill has a formatting error | Check that it's valid Markdown |
| A hook has a JSON error | Validate with python -m json.tool |
| Dependencies not installed | Run pip install -e ".[dev]" or npm install |
| The entry point doesn't run | Check that cli.py / index.ts has the right structure |
Tips for Explore
- Be specific about what you want analyzed. "Analyze everything" is worse than "Analyze the structure, CLAUDE.md, and skills."
- Ask it NOT to make changes. The phrase "Don't make any changes, just analyze" is the key. Without it, Claude might start fixing things on its own.
- Check the output. Claude can get the analysis wrong. If it says something exists and it doesn't, correct it.
Step 3: Plan — Design the CLI
Now that you know the setup is correct, design the implementation. Turn on Plan mode so Claude produces a plan without executing anything.
The Plan prompt
Type this into Claude Code (adapt it to the project you chose):
Example for the notes CLI:
/plan Design the implementation of my notes CLI with these 3 commands:
1. "add" — Create a note with text and an optional tag
2. "list" — List all notes, with an optional tag filter
3. "search" — Search notes by text
Consider:
- The architecture defined in CLAUDE.md
- Storage: a JSON file at ~/.notes/notes.json
- Each note has: id, text, tag (optional), timestamp
- The output must be formatted and readable
Give me a detailed plan with files to create, implementation order,
and dependencies between components.
Example for the file organizer:
/plan Design the implementation of my file organizer CLI with
these 3 commands:
1. "scan" — Scan a directory and show a summary by type
2. "organize" — Organize files into subdirectories by type
3. "undo" — Revert the last organization
Consider:
- The architecture defined in CLAUDE.md
- Categories: images, documents, code, media, others
- Save a history of moves so undo works
- Output as a formatted table
Give me a detailed plan with files to create, implementation order,
and dependencies.
Example for the health checker:
/plan Design the implementation of my health checker CLI with these
3 commands:
1. "add" — Add an endpoint with a name and a URL
2. "run" — Run a health check against every endpoint
3. "report" — Generate a report in table or JSON format
Consider:
- The architecture defined in CLAUDE.md
- Storage: a JSON file at ~/.healthcheck/endpoints.json
- Show status code, response time, and state
- Async requests so multiple endpoints are checked in parallel
Give me a detailed plan with files to create, implementation
order, and dependencies.
What to expect from the plan
Claude should produce a structured plan like this:
## Plan: Notes CLI
### Files to create
1. src/commands/add.py (CREATE) — Command to add notes
2. src/commands/list.py (CREATE) — Command to list notes
3. src/commands/search.py (CREATE) — Command to search notes
4. src/utils.py (CREATE) — Storage manager and formatting
5. src/cli.py (MODIFY) — Register the 3 commands
### Storage architecture
~/.notes/ └── notes.json { "notes": [ { "id": 1, "text": "...", "tag": "work", "created_at": "2026-02-28T10:30:00" } ], "next_id": 2 }
### Implementation order
1. **src/utils.py** — Storage manager (load_notes, save_notes,
get_notes_path) and output formatter. It gets implemented
first because all 3 commands depend on it.
2. **src/commands/add.py** — First command. Depends on utils
to save the note. It's the simplest one: takes text, creates
the note, saves it.
3. **src/commands/list.py** — Second command. Depends on utils
to load notes. Adds a tag filter with --tag.
4. **src/commands/search.py** — Third command. Depends on utils
to load notes and filter them by text.
5. **src/cli.py** — Register the 3 commands. It gets modified
after each command so you can test incrementally.
### Dependencies between components
src/utils.py ├── load_notes() → Reads ~/.notes/notes.json ├── save_notes() → Writes ~/.notes/notes.json ├── get_notes_path() → Returns the path to the file └── format_note() → Formats a note for output
src/commands/add.py → uses utils.save_notes, utils.load_notes src/commands/list.py → uses utils.load_notes, utils.format_note src/commands/search.py → uses utils.load_notes, utils.format_note
### Considerations
- Create the ~/.notes/ directory if it doesn't exist
- Handle the case of an empty or missing JSON file
- Auto-incrementing IDs
- Timestamps in ISO 8601
- Output with click.echo(), optional colors with click.style()
### Risks
- If two instances write at the same time → JSON corruption
(acceptable for this project's scope)
- The file can grow large → we don't implement pagination
in list (out of scope)
Shall I proceed with the implementation?
Evaluating the plan
Before approving, review these points:
| Aspect | What to check |
|---|---|
| Completeness | Does it cover all 3 commands? Does it include utils? |
| Order | Are the dependencies in the right order? |
| Consistency | Is the plan coherent with CLAUDE.md? |
| Scope | Is it achievable in ~35 minutes of implementation? |
| Risks | Did it identify limitations? Are they acceptable? |
Step 4: Iterate on the plan
The plan doesn't have to be perfect on the first pass. The power of Plan mode is that you can iterate before writing any code.
Iteration 1: Add detail
If part of the plan is too generic:
The plan looks good. But I need more detail on src/utils.py.
What exact functions will it have? What parameters do they take?
What do they return? Give me the signature of each function.
Claude updates the plan:
### src/utils.py — Function detail
def get_notes_path() -> Path:
"""Returns ~/.notes/notes.json, creates the directory if missing."""
def load_notes() -> dict:
"""Reads the JSON file. Returns {"notes": [], "next_id": 1}
if it doesn't exist."""
def save_notes(data: dict) -> None:
"""Writes the dict to the JSON file with indentation."""
def format_note(note: dict, detail: bool = False) -> str:
"""Formats a note for display.
Basic format: #42 Note text [tag] 2 min ago
Detail format: includes the full timestamp and metadata."""
def time_ago(timestamp: str) -> str:
"""Converts an ISO timestamp to 'X min/hours/days ago'."""
Iteration 2: Change a decision
If you disagree with something in the plan:
I don't want to use a JSON file in the home directory. I'd rather
the storage be a .notes.json file in the current directory.
That way each project can have its own notes.
Update the plan.
Claude adjusts:
### Change: Local storage
Instead of ~/.notes/notes.json, the file will be .notes.json
in the current directory (cwd).
Changes to the plan:
- get_notes_path() → returns Path(".notes.json")
- No need to create a directory
- Add .notes.json to .gitignore
- Document in CLAUDE.md that storage is local
Iteration 3: Simplify
If the plan is too complex for the scope:
The "time_ago" format adds unnecessary complexity. Better to
show the timestamp directly in a short format (Feb 28, 10:30).
Simplify it.
Claude adjusts:
### Simplification
We drop time_ago(). Instead, format_note() shows
the timestamp as "Feb 28, 10:30" using strftime.
Reduction: -1 function, -15 estimated lines.
How many iterations to do
- Minimum: 1 iteration (review and adjust at least something)
- Ideal: 2-3 iterations
- Maximum: 4-5 (past 5, you're probably over-analyzing)
The goal isn't a perfect plan — it's a plan good enough to start implementing with confidence.
Step 5: Approve the plan
When you're happy with the plan, approve it explicitly:
The plan looks good. The structure is right, the
dependencies are clear, and the scope is manageable.
We'll implement it in the next session following this plan.
Don't implement anything yet — just confirm you understood the
full plan.
Claude confirms:
Understood. The plan is approved:
1. src/utils.py — Storage and formatting (first)
2. src/commands/add.py — add command (second)
3. src/commands/list.py — list command (third)
4. src/commands/search.py — search command (fourth)
5. src/cli.py — Register commands (incremental)
Ready to implement whenever you say. Each step will follow
CLAUDE.md's conventions and the skills' templates.
Why not implement in the same session?
You can — nothing stops you. But there are reasons to separate Plan from Code:
- Context window: The Plan session already consumed tokens. A new session starts with fresh context.
- Reflection: You can think about the plan before implementing. Sometimes you spot improvements after stepping away.
- Practice: Treating Explore → Plan → Code as distinct phases trains the habit of the professional workflow.
If you'd rather continue in the same session, go straight to Capsule 04.
A complete example conversation
Here's a full Explore + Plan conversation for reference. This example uses the notes CLI with Python:
You:
Explore this project and give me a report on its current state.
What files exist? Is CLAUDE.md complete?
Are the skills and hooks configured? Don't make any changes.
Claude:
[Reads directories, CLAUDE.md, skills, settings.json]
## Project report: notes-cli
### Structure ✅
- CLAUDE.md (52 lines)
- .claude/skills/create-command/SKILL.md ✅
- .claude/skills/add-tests/SKILL.md ✅
- .claude/settings.json (2 hooks) ✅
- src/cli.py (Click entry point) ✅
- pyproject.toml ✅
### CLAUDE.md ✅
6 complete sections, < 200 lines, clear conventions.
Note: the command names in the structure
(command_one, etc.) should be updated to add, list, search
after planning.
### Skills ✅
Both skills have templates, instructions, and rules.
### Hooks ✅
PostToolUse → ruff, PreToolUse → pytest before commit.
### State: Ready for planning.
───────────────────────────────────────────
You:
Good catch on the names in CLAUDE.md. We'll
update them after planning.
/plan Design the implementation of my notes CLI with 3 commands:
1. "add" — Create a note with text and an optional tag
2. "list" — List notes with a tag filter
3. "search" — Search notes by text
Storage: .notes.json in the current directory.
Claude:
[Produces a detailed plan]
## Plan: notes-cli
### Files to create/modify
1. src/utils.py (CREATE) — Storage and formatting
2. src/commands/__init__.py (CREATE) — Package
3. src/commands/add.py (CREATE) — add command
4. src/commands/list_notes.py (CREATE) — list command
5. src/commands/search.py (CREATE) — search command
6. src/cli.py (MODIFY) — Register commands
### Note on naming
The file for "list" is called list_notes.py to avoid
a conflict with Python's built-in list.
### Implementation order
[detailed plan...]
### Risks
[identified limitations...]
Shall I proceed?
───────────────────────────────────────────
You:
Good thinking on list_notes.py. Two adjustments:
1. Add a --json flag to list for JSON output
2. Make search case-insensitive
Update the plan.
Claude:
[Updates the plan with the adjustments]
### Changes to the plan
1. list_notes.py: Added the --json/-j flag
- With --json: output via json.dumps(notes, indent=2)
- Without it: formatted output (default)
2. search.py: Case-insensitive search
- Lowercase both the query and the note text
before comparing
The rest of the plan stays the same.
Ready to implement?
───────────────────────────────────────────
You:
The plan is approved. Don't implement yet. Confirm
you're clear on the full plan.
Claude:
Plan confirmed. I'll implement in this order:
1. src/utils.py — 5 functions (load, save, path, format, etc.)
2. src/commands/add.py — @click.command with a text arg and --tag
3. src/commands/list_notes.py — @click.command with --tag and --json
4. src/commands/search.py — @click.command with a query arg, case-insensitive
5. src/cli.py — Register the 3 commands
Storage in a local .notes.json. CLAUDE.md conventions.
Ready when you are.
Common mistakes in this phase
Mistake 1: Skipping Explore
The problem: Going straight to Plan without verifying the setup is correct.
The consequence: Claude plans on top of a broken base. If CLAUDE.md has an error or a skill is missing, the plan inherits it.
The fix: Always run Explore first. Two minutes that save you twenty.
Mistake 2: A plan that's too vague
The problem: Accepting a plan like "create the 3 commands using the project's structure."
The consequence: Claude interprets it freely and the result may not be what you expected.
The fix: The plan must include:
- The specific files to create/modify
- The implementation order
- Dependencies between components
- The main functions or methods
Mistake 3: A plan that's too detailed
The problem: Asking for a plan that includes every line of code.
The consequence: The plan turns into the implementation, burning context for nothing.
The fix: The plan is a high-level design, not pseudocode. Implementation details belong to the Code phase.
Mistake 4: Not iterating
The problem: Accepting the first plan without reviewing it.
The consequence: You lose the chance to shape the solution before any code gets written.
The fix: Read the whole plan. Do at least 1 iteration. Question decisions you don't understand.
Mistake 5: Too many iterations
The problem: 10 rounds of feedback and never approving.
The consequence: Analysis paralysis. The plan is never perfect — at some point it's better to implement and adjust as you go.
The fix: 4-5 iterations max. If you're still unhappy after 5 rounds, the problem may be the scope (too big) or the ambiguity (redefine the goal).
Checklist: is your plan ready?
Before moving to Capsule 04, check that:
- You ran Explore and the setup is correct
- The plan lists every file to create/modify
- The implementation order respects the dependencies
- Every command has its file and its functionality defined
- The plan is coherent with CLAUDE.md
- You iterated at least once with feedback
- The plan is doable in ~35 minutes
- You approved the plan explicitly
If everything is checked, you're ready for Phase 3: Build.
Tips for giving good feedback while planning
Be specific, not vague
❌ "I don't like the plan, change it"
✅ "The list command should have a --json flag. Add it to the plan."
Explain the why
❌ "Don't use a file in the home directory"
✅ "I prefer local storage (.notes.json in cwd) because I want
each project to have its own notes"
Accept trade-offs
✅ "I understand we're not implementing pagination. That's acceptable
for this scope."
Question what you don't understand
✅ "Why is the file called list_notes.py and not list.py?"
Give constructive feedback
✅ "I like the separation in utils.py. Also add a
function to validate that the text isn't empty."
Comparison: with Plan vs without Plan
Without Plan (straight to Code)
You: "Implement a notes CLI with 3 commands"
Claude: [Starts creating files immediately]
→ Picks a structure you may not like
→ Uses storage in the home directory (you wanted local)
→ Doesn't include --json in list (it didn't know you wanted it)
→ Search is case-sensitive (you wanted insensitive)
Result: 3-4 rounds of corrections after implementing
With Plan (Explore → Plan → Code)
You: "Explore the project. Then plan the CLI."
Claude: [Analyzes, designs, presents a plan]
You: "Change storage to local, add --json, make search insensitive"
Claude: [Updates the plan]
You: "Approved. Implement."
Claude: [Implements exactly what was agreed]
Result: 0-1 corrections. The code fits on the first try.
Measurable impact
| Metric | Without Plan | With Plan |
|---|---|---|
| Post-implementation corrections | 3-5 | 0-1 |
| Total time | More (from redoing work) | Less |
| Context window consumption | High (code iterations) | Low (text iterations) |
| Satisfaction with the result | Variable | High |
The cheapest iteration is the one that happens in text (Plan), not in code (Code). Changing a line in the plan costs 0 implementation tokens. Changing a line in implemented code can mean adjustments across 3-4 files.
Troubleshooting
"Claude won't go into Plan mode"
If you type /plan and Claude starts implementing right away:
Stop. Don't implement anything. I only want the plan.
Give me a design with files to create, implementation order,
and dependencies. Don't write any code yet.
The key phrase is "don't implement anything" or "don't write any code yet".
"The plan is too short"
If Claude gives you a 3-line plan:
The plan is too shallow. I need more detail:
- The exact list of files to create
- The main functions in each file
- Dependencies between modules
- What gets implemented first and why
"The plan includes technologies I don't want"
I don't want to use SQLite for storage. I want a simple JSON
file. Update the plan.
Claude should adjust without pushback. If it insists, be firm: "Use JSON. Not SQLite."
"I don't know what feedback to give"
Ask yourself:
- Are the files where I'd put them?
- Does the implementation order make sense?
- Is anything missing from the plan?
- Is the scope realistic for 35 minutes?
- Are the technical decisions the ones I'd make?
If the answer to all of them is yes, approve the plan.
Summary
What you did in this capsule:
- Opened Claude Code in your project and verified it reads CLAUDE.md
- Ran Explore to analyze the state of the setup
- Produced a plan with
/planto design your CLI's 3 commands - Iterated on the plan with at least 1 round of feedback
- Approved the plan, ready to implement
The Explore → Plan phase gives you confidence that:
- Your setup is correct (you won't discover errors halfway through the implementation)
- Your design is thought through (you won't improvise the architecture)
- Claude has a clear plan (the instructions are explicit, not ambiguous)
Connection to the professional workflow:
The Explore → Plan sequence isn't an academic whim. It's the same sequence the best engineers use:
- Understand the terrain (Explore)
- Design the solution (Plan)
- Execute with confidence (Code)
The difference is that with Claude Code, each phase has a concrete mechanism. It isn't an abstract concept — it's a tool you use with specific prompts.
Next capsule: 04 - Building with Claude Code — where you'll implement the 3 commands using Agent mode, skills, and hooks.