Week 16 of 16

Capstone: Build Day 1

Get the core working. Don't polish. Don't extend. Prove the concept first.

Day 78 90+ minutes Build

Day 78 of 80

Start With the Core

The Core Feature Test

Before you write any code, answer this question: what is the one thing this project does that makes it worth building? That's the core. Start there.

For the Shot List Processor, the core is: give Claude a brief, get back a list of shot descriptions. Not the async generation, not the HTML export, not the CLI flags. Just that one thing. Get it working first.

For the INFLECT Extension, the core is: the new feature does what you planned. The existing app still works.

For the DVP Workflow Dashboard, the core is: prompts can be stored and retrieved. Not the UI, not the export. Just the data layer.

Don't polish yet. Don't add features yet. Don't worry about error handling yet. Build the one thing that proves the concept works — then layer everything else on top of it.

The Build Order

Always in This Order

No matter what you're building, the sequence is the same:

  1. Get data flowing from input to output — even if it's ugly. Print statements are fine. Hardcoded test data is fine. The goal is end-to-end: something goes in, something comes out.
  2. Add validation and error handling — once the happy path works, think about what can go wrong. Bad input, API failures, missing files. Handle them gracefully.
  3. Polish and extend — clean up the code, add the secondary features, write the README. This is Day 79's job, not today's.

If you find yourself writing error handling before the happy path works, stop. You're optimizing code that doesn't exist yet.

When You Get Stuck

The Debugging Ladder

You will get stuck. That's not a sign that something's wrong — it's the job. Here's the order of operations when it happens:

  1. Read the error message carefully. Python's error messages are specific. "KeyError: 'shots'" tells you exactly what key is missing and in which operation. Most errors are solved by the error message alone if you actually read it.
  2. Add a print() to see what data looks like at that point. Before the thing that's failing, print the variable. Is it what you expected? If not, the problem is earlier in the chain, not where the error fires.
  3. Describe the problem to Claude in Cursor. Use this exact format: "I'm trying to X. I've tried Y. I'm seeing Z." The more specific you are, the better the answer. Don't paste the code and ask "why doesn't this work" — that's not a question.
  4. Check the relevant week's lesson. If you're stuck on an async issue, go back to Week 13. If it's a database query, go back to Week 11. The pattern you need is in those notes.
Don't Spend More Than 20 Minutes Stuck on One Thing

20 minutes of focused debugging is productive. 45 minutes of frustrated spinning is not. After 20 minutes, step back, describe the problem to Claude clearly, and get unstuck. You have a build to finish.

Concrete First Steps by Project

Shot List Processor: Start With Extraction

Don't touch async yet. Don't build the CLI yet. Create extractor.py with a single function: take a string (the brief text), call Claude, return a list of shot descriptions. Hardcode a sample brief as a string to test with. Get Claude to return 5 clean shot descriptions. That's it. That's today's first milestone.

extractor.py — first version python
import anthropic

client = anthropic.Anthropic()

def extract_shots(brief_text: str) -> list[str]:
    """Extract a list of shot descriptions from a brief."""
    response = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        system="""You are a cinematographer reading a production brief.
Extract 5-10 distinct shots from the brief. Each shot is one
atomic visual moment. Return them as a numbered list, one per line.
Nothing else — just the numbered list of shot descriptions.""",
        messages=[{"role": "user", "content": brief_text}]
    )
    raw = response.content[0].text
    # Parse the numbered list into a Python list
    shots = [
        line.split(". ", 1)[1].strip()
        for line in raw.strip().splitlines()
        if line.strip() and line[0].isdigit()
    ]
    return shots

# Quick test — run this file directly to check it works
if __name__ == "__main__":
    sample = """A coastal sunrise. The lighthouse keeper walks down to the
    dock. He checks the nets — empty. A pelican lands nearby. He looks
    out at the horizon, shielding his eyes."""
    shots = extract_shots(sample)
    for i, shot in enumerate(shots, 1):
        print(f"{i}. {shot}")
This is a complete working spike. Run it. If you get 5 shot descriptions back, the hardest part of the project is solved. Now you can build the rest around this working core.
INFLECT Extension: Read the Codebase First

Don't write a single line of new code until you've read the file that's most relevant to your feature. Understand the existing patterns: how routes are defined, how Claude is called, how data is stored and retrieved. Find two or three examples of the pattern you'll need to follow — then write code that looks like the code that's already there.

Opening a codebase with fresh eyes and finding your way around is a skill. Take 20 minutes on it before building anything. It'll save you an hour of mismatched patterns later.

DVP Workflow Dashboard: Start With the Data Model

Create the database schema first. Write the SQL or SQLAlchemy models for your tables. Add a few rows of test data directly in Python — don't build the UI yet. Write the two or three queries you'll need most: get all prompts for a project, get all prompts for a scene, mark a prompt as used. Get those working and returning the right data before a single HTML template exists.

The End-of-Day Test

Know This Before You Start

Before you write your first line of code today, answer this: what is the one thing you should be able to demonstrate at the end of today's session? Not "progress" — a specific, concrete output.

For the Shot List Processor: "I can call extract_shots() with a text brief and get back a list of shot descriptions."

For INFLECT: "The new feature is callable and returns the expected output, even if the UI isn't wired up yet."

For the Dashboard: "I can write a prompt to the database and read it back with a query."

Hold yourself to that standard. If you hit it with time to spare, do more. If you're not going to hit it, narrow the scope until you can.

End of Day Checklist