🏆 Capstone Project

Build a URL Shortener — Three Ways

Build the same URL Shortener microservice using Claude Code, then Gemini CLI, then GitHub Copilot CLI. Document your experience at each step. By the end, you'll have first-hand evidence — not theory — for which tool works best for your workflow.

3–4 hours total
Python (FastAPI) + SQLite
All 3 tools required
Claude Code
Gemini CLI
GitHub Copilot CLI
Capstone Section 1

What You'll Build

A URL shortener is the ideal capstone project: small enough to complete in a single session with each tool, yet rich enough to exercise every capability — scaffolding, database design, API design, authentication, testing, documentation, and security review.

Feature Specification
POST /shorten Accept a long URL, generate a 6-char alphanumeric code, store in SQLite, return short URL
GET /{code} Look up code in SQLite, return HTTP 301 redirect to long URL
GET /stats/{code} Return click count, creation date, original URL for a given code
Click analytics Increment click counter on every redirect; store timestamp of each click
Error handling 404 for unknown codes, 422 for invalid URLs, 429 for rate limiting (optional stretch goal)
Tests pytest tests covering all three endpoints, including edge cases
Documentation README.md with setup instructions + auto-generated OpenAPI spec
Prerequisites

Python 3.11+, Node.js 18+ (for some Claude Code tools), git. Claude Code installed and authenticated. Gemini CLI installed and authenticated. GitHub CLI with Copilot extension installed (gh extension install github/gh-copilot). VS Code with Copilot extension for Round 3. Estimated time: 60–90 minutes per round.

Why URL shortener?

It has a clear spec (no ambiguity), requires real database design (not just hello world), has obvious security concerns (URL validation, redirect safety, rate limiting), and the full feature set takes 45–90 minutes with each tool — long enough to learn something, short enough to complete. It also has a well-understood reference implementation so you can evaluate AI output quality accurately.

Set up a fresh directory before each round. This simulates starting from scratch with each tool:

PowerShell — workspace setup
# Create three separate directories — one per round
New-Item -ItemType Directory -Force url-shortener-claude
New-Item -ItemType Directory -Force url-shortener-gemini
New-Item -ItemType Directory -Force url-shortener-copilot

# Track your observations in a journal file
New-Item -ItemType File url-shortener-journal.md
Add-Content url-shortener-journal.md "# URL Shortener Capstone Journal`n`n## Round 1: Claude Code`n`n## Round 2: Gemini CLI`n`n## Round 3: Copilot CLI`n"
Bash — workspace setup
# Create three separate directories — one per round
mkdir url-shortener-{claude,gemini,copilot}

# Track your observations in a journal file
cat > url-shortener-journal.md << 'EOF'
# URL Shortener Capstone Journal

## Round 1: Claude Code

## Round 2: Gemini CLI

## Round 3: Copilot CLI
EOF
Capstone Section 2

Round 1: Claude Code

Start the timer. Navigate to url-shortener-claude/ and run Claude Code. Follow these four steps in order, documenting your observations after each one.

Round 1 Claude Code — 4 steps
1
Bootstrap the project
Navigate to your claude directory and run Claude Code with the scaffolding prompt. Observe: does it ask clarifying questions? Does it generate a complete, working file structure?
PowerShell — Claude Code scaffolding
Set-Location url-shortener-claude
claude "scaffold a FastAPI URL shortener with SQLite backend. Requirements:
- POST /shorten: accept long_url, generate 6-char alphanumeric code, return short_url
- GET /{code}: 301 redirect to original URL, increment click count
- GET /stats/{code}: return clicks, created_at, original URL
- SQLAlchemy for SQLite ORM
- pydantic models for request/response validation
- Full error handling: 404, 422, rate limit stub
- requirements.txt and uvicorn startup command
Make it production-ready, not a toy."
Bash — Claude Code scaffolding
cd url-shortener-claude
claude "scaffold a FastAPI URL shortener with SQLite backend. Requirements:
- POST /shorten: accept long_url, generate 6-char alphanumeric code, return short_url
- GET /{code}: 301 redirect to original URL, increment click count
- GET /stats/{code}: return clicks, created_at, original URL
- SQLAlchemy for SQLite ORM
- pydantic models for request/response validation
- Full error handling: 404, 422, rate limit stub
- requirements.txt and uvicorn startup command
Make it production-ready, not a toy."
Record: time to first working file, number of files generated, whether it ran without errors after pip install -r requirements.txt && uvicorn main:app --reload.
2
Add tests
Ask Claude Code to add comprehensive pytest tests. Observe: does it understand the codebase it just created? Does it generate realistic test data and edge cases?
Claude Code — add tests
claude "add pytest tests for all endpoints. Include:
- Test POST /shorten with valid URL
- Test POST /shorten with invalid URL (expect 422)
- Test GET /{code} redirect with valid code
- Test GET /{code} with unknown code (expect 404)
- Test GET /stats/{code} click count increments correctly
- Test that duplicate URLs can be shortened (multiple codes allowed)
Use pytest fixtures for test database isolation."
Run: pytest -v. Record: how many tests pass on first run? Did it need iterations to fix failures?
3
Security review
Ask Claude Code to review the code it just wrote for security issues. This is a real test: can it critique its own output objectively?
Claude Code — security review
claude "review this URL shortener code for security issues. Look for:
1. Open redirect vulnerabilities (are we validating that URLs are safe?)
2. SQLite injection risks
3. Missing rate limiting on /shorten endpoint
4. Short code collision probability and birthday attack risk
5. Analytics data privacy (storing IPs?)
6. Any other security concerns for a production deployment
For each issue found: explain the risk, show the vulnerable code, and provide a fix."
Record: how many issues did it find? Were the findings accurate and actionable? Did it implement the fixes when asked?
4
Generate documentation
Ask for complete documentation including README and OpenAPI spec comments.
Claude Code — documentation
claude "generate:
1. A complete README.md with: project description, prerequisites, installation, usage examples with curl commands, API reference table
2. Add FastAPI docstrings to all endpoints with example request/response JSON
3. A .env.example file listing all configurable environment variables
Make the README good enough that a new developer can set this up in 5 minutes."
Record: total time for Round 1. Quality rating (1–5) for each output. Note one thing that surprised you — positively or negatively.
Capstone Section 3

Round 2: Gemini CLI

Reset the timer. Navigate to url-shortener-gemini/. You'll use Gemini CLI's Plan Mode for the scaffold step and direct prompts for the remaining three.

Round 2 Gemini CLI — 4 steps
1
Bootstrap using Plan Mode
Use Gemini CLI's Plan Mode — it will propose the architecture before writing any code. Review the plan, approve it, and watch it execute. Compare the plan quality to Claude's direct generation.
PowerShell — Gemini CLI with Plan Mode
Set-Location url-shortener-gemini

# WHAT: Start Gemini CLI in Plan Mode — it proposes architecture before coding
# WHY:  Plan Mode lets you review and edit the approach before execution
# GOTCHA: Type 'plan' at the prompt, then enter your task description

gemini
# At the GEMINI prompt, type:
# plan scaffold a FastAPI URL shortener with SQLite, same spec as before:
# POST /shorten, GET /{code} redirect, GET /stats/{code}, full error handling,
# SQLAlchemy ORM, pydantic models, requirements.txt. Production quality.

# Review the plan Gemini proposes.
# Type 'approve' to execute, or edit the plan first.
Bash — Gemini CLI with Plan Mode
cd url-shortener-gemini

# WHAT: Start Gemini CLI in Plan Mode — it proposes architecture before coding
# WHY:  Plan Mode lets you review and edit the approach before execution
# GOTCHA: Type 'plan' at the prompt, then enter your task description

gemini
# At the GEMINI prompt, type:
# plan scaffold a FastAPI URL shortener with SQLite, same spec as before:
# POST /shorten, GET /{code} redirect, GET /stats/{code}, full error handling,
# SQLAlchemy ORM, pydantic models, requirements.txt. Production quality.

# Review the plan Gemini proposes.
# Type 'approve' to execute, or edit the plan first.
Record: Was the plan accurate? Did you modify it? How did the final output compare to Claude's in completeness and correctness?
2
Add tests using a skill.md
Create a skill.md file that defines your testing standards, then reference it in your Gemini prompt. This demonstrates Gemini's context injection pattern.
Gemini CLI — skill.md for test generation
# First: create the skill.md file
# In PowerShell: New-Item -ItemType File skill.md then edit it
# In Bash: create with your editor or:
cat > skill.md << 'EOF'
# Testing Standards

All tests must:
- Use pytest fixtures for database isolation (test_db fixture)
- Cover the happy path AND at least 2 error cases per endpoint
- Assert on HTTP status codes AND response body fields
- Use TestClient from fastapi.testclient
- Run in under 5 seconds total
EOF

# Then in Gemini CLI:
gemini "following @skill.md, add pytest tests for all three endpoints.
Same coverage requirements: POST /shorten valid + invalid,
GET redirect valid + 404, GET /stats with count increment verification."
3
Security review
Same security review prompt as Round 1. Compare the depth and accuracy of findings between Gemini Pro and claude-sonnet-4-6.
Gemini CLI — security review
gemini "review this URL shortener for security issues:
1. Open redirect vulnerabilities
2. SQL injection risks
3. Missing rate limiting
4. Short code collision/birthday attack risk
5. Any other production security concerns
For each issue: show the vulnerable code, explain the risk, provide a fix."
4
Documentation
Same documentation request as Round 1. Note the quality difference, especially in README completeness and API example accuracy.
Gemini CLI — documentation
gemini "generate: (1) complete README.md with install + usage + curl examples + API reference,
(2) FastAPI docstrings with example JSON on all endpoints,
(3) .env.example file. Target: new developer running in 5 minutes."
Record: total time for Round 2. Compare to Round 1 on quality and speed. Note where Gemini surprised you.
Capstone Section 4

Round 3: GitHub Copilot CLI

Round 3 is the most instructive because it shows the gap. GitHub Copilot CLI (gh copilot) is not a code generation tool — it is a shell command assistant. You will need to use VS Code with Copilot Chat for the actual code generation. This round documents where Copilot excels and where manual work remains.

Adjust expectations for Round 3

This round takes longer because Copilot CLI cannot autonomously scaffold a FastAPI project. You will use VS Code + Copilot Chat for code generation (this is Copilot's actual strength), and gh copilot suggest for shell commands. Copilot CLI's terminal experience is the surface this course covers — and this round shows exactly where its limits are.

Round 3 GitHub Copilot CLI + VS Code Copilot Chat
1
Bootstrap: VS Code Copilot Chat (not CLI)
The gh copilot CLI cannot scaffold a project. Open VS Code, open url-shortener-copilot/, and use the Copilot Chat panel (Ctrl+Shift+I) with the same scaffolding prompt. This is Copilot's actual home — the IDE.
VS Code Copilot Chat panel — scaffolding prompt
# In VS Code Copilot Chat (Ctrl+Shift+I), type:
# "scaffold a FastAPI URL shortener with SQLite backend.
#  POST /shorten, GET /{code} redirect, GET /stats/{code}.
#  SQLAlchemy ORM, pydantic models, full error handling, requirements.txt."

# Note what Copilot Chat generates vs. what claude/gemini generated.
# Does it create files? Does it ask for workspace access?

# For shell commands during setup, use gh copilot:
gh copilot suggest -t shell "create a Python virtual environment and install fastapi sqlalchemy uvicorn"
# → Copilot suggests: python -m venv venv && source venv/bin/activate && pip install fastapi sqlalchemy uvicorn
# You approve and run it.
Record: Did Copilot Chat create files directly, or just suggest code to copy-paste? How many manual steps were required compared to Claude Code?
2
Tests: inline completion is Copilot's strength
This is where Copilot shines. Open test_main.py in VS Code and start typing a test function — Copilot will autocomplete full test implementations. This is faster than any prompting workflow for test generation IF you have the context open in the IDE.
VS Code — Copilot inline completion for tests
# Open test_main.py in VS Code. Type the function signature:
# Copilot will autocomplete the entire test body as you type.

import pytest
from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_shorten_valid_url():
    # Start typing here — Copilot will suggest the full test body
    # based on what it sees in main.py (if that file is open in the editor)
    ...

def test_shorten_invalid_url():
    # Again, let Copilot complete — notice how accurate it is with context
    ...
Record: How accurate were Copilot's inline completions? Did it correctly understand the FastAPI models? Compare to the full test files Claude and Gemini generated autonomously.
3
Security review: gh copilot limitations become clear
Try using gh copilot suggest for the security review. Notice what it returns — a shell command, not a code review. This is the fundamental limitation of the CLI surface.
PowerShell — gh copilot security attempt
# ATTEMPT: Use gh copilot for security review
gh copilot suggest -t shell "review main.py for open redirect vulnerabilities and SQL injection"
# ACTUAL OUTPUT: A shell command like:
# grep -n "redirect\|sql\|query" main.py
# NOT a security review — just a grep command

# WHAT WORKS INSTEAD: Use VS Code Copilot Chat for code review
# In VS Code Chat: "Review main.py for open redirect vulnerabilities,
# SQL injection risks, and rate limiting gaps"
# This gives a real review — but requires the IDE, not the terminal
Bash — gh copilot security attempt
# ATTEMPT: Use gh copilot for security review
gh copilot suggest -t shell "review main.py for open redirect vulnerabilities and SQL injection"
# ACTUAL OUTPUT: A shell command like:
# grep -n "redirect\|sql\|query" main.py
# NOT a security review — just a grep command

# WHAT WORKS INSTEAD: Use VS Code Copilot Chat for code review
# In VS Code Chat: "Review main.py for open redirect vulnerabilities,
# SQL injection risks, and rate limiting gaps"
# This gives a real review — but requires the IDE, not the terminal
Record: What did gh copilot suggest actually return? How did VS Code Copilot Chat's review compare to Claude Code's review in depth and actionability?
4
Documentation: where gh copilot helps
Use gh copilot explain on individual commands, and VS Code Copilot Chat for the README. Note where Copilot's strengths compensate for its CLI limitations.
PowerShell — gh copilot for command docs
# gh copilot explain is excellent for explaining commands
gh copilot explain "uvicorn main:app --reload --host 0.0.0.0 --port 8000"
# → Clear explanation of each flag. This is where gh copilot is genuinely useful.

# For README generation, use VS Code Chat:
# "Write a README.md for this FastAPI URL shortener. Include:
#  prerequisites, installation steps, curl examples, API reference"
# Then copy-paste from VS Code to README.md manually.

# The gap: Claude Code and Gemini wrote README.md directly to disk.
# Copilot Chat requires manual copy-paste to file.
# This is the fundamental IDE-vs-terminal distinction.
Bash — gh copilot for command docs
# gh copilot explain is excellent for explaining commands
gh copilot explain "uvicorn main:app --reload --host 0.0.0.0 --port 8000"
# → Clear explanation of each flag. This is where gh copilot is genuinely useful.

# For README generation, use VS Code Chat:
# "Write a README.md for this FastAPI URL shortener. Include:
#  prerequisites, installation steps, curl examples, API reference"
# Then copy-paste from VS Code to README.md manually.

# The gap: Claude Code and Gemini wrote README.md directly to disk.
# Copilot Chat requires manual copy-paste to file.
# This is the fundamental IDE-vs-terminal distinction.
Record: total time for Round 3. How much was spent in the IDE vs. terminal? How many manual steps (copy-paste, file saves) did Copilot require that Claude and Gemini handled automatically?
Capstone Section 5

Scoring Rubric

After completing all three rounds, fill in your scores below. The reference scoring reflects typical results — your experience may differ based on how you wrote prompts and which model tier you used.

Claude Code — typical scores
Code quality (1–5)
Time to first working version20–35 min
Test coverage quality
Security review depth
Documentation quality
Developer experience
Cost for this project~$0.08–0.20
Gemini CLI — typical scores
Code quality (1–5)
Time to first working version25–45 min
Test coverage quality
Security review depth
Documentation quality
Developer experience
Cost for this project$0 (free tier)
Copilot CLI — typical scores
Code quality (1–5)
Time to first working version45–75 min (IDE required)
Test coverage quality
Security review depth
Documentation quality
Developer experience
Cost for this projectIncluded in subscription
Why Copilot tests score high despite CLI limitations

Copilot's test completion in VS Code often matches or exceeds Claude and Gemini — because it has full codebase context in the IDE and its training data includes massive amounts of pytest/unittest patterns. The CLI limitation does not affect IDE-based test writing. This is the hybrid stack insight in action: use the right tool for each job.

Capstone Section 6

Your Verdict

Fill in your own scores and reflections. These prompts are designed to surface insights about your specific workflow — not to confirm the "expected" answers.

Your Capstone Reflection

Responses are saved to localStorage in this browser only — not sent anywhere.

Capstone Section 7

Next Steps

You have completed the AI CLI Tools Compared course and capstone. Here is where to go next:

Share your capstone results

The most valuable outcome of this capstone is your personal comparison data. Share your journal (url-shortener-journal.md) and scoring rubric in the community Discord. Over time, the community's aggregated results will reveal real-world performance patterns that no single reviewer can observe. Your data contributes to a collective understanding of where each tool excels.

  • Completed Round 1 with Claude Code (all 4 steps)
  • Completed Round 2 with Gemini CLI (all 4 steps)
  • Completed Round 3 with GitHub Copilot CLI + VS Code (all 4 steps)
  • Filled in scoring rubric with your actual scores
  • Completed the verdict reflection with honest observations
  • Saved journal to url-shortener-journal.md
  • Decided on your personal tool stack going forward