Behind the Build: AI Pair Programming the Python SSG
In a previous post, I detailed the features and workflow of the simple Python Static Site Generator (SSG) that powers this digital workshop. I mentioned its rapid development – roughly 5-6 hours of hands-on coding time spanning less than two days. But how exactly did that happen? How does one go from zero to a functional SSG, including templating, frontmatter parsing, asset handling, and deployment integration, so quickly?
The secret sauce wasn't some hidden coding superpower; it was intensive pair programming with an AI assistant. This post delves into that process, starting with the very seed that kicked it all off.
The Starting Point: Defining the Destination
Before writing a single line of Python, the crucial first step was defining what needed to be built. Instead of just jumping into code, I drafted a clear "seed document." This wasn't just a vague idea; it was a structured plan outlining:
- Overall Goals: What the SSG should achieve at a high level.
- Core Philosophy: Simplicity, control, using familiar tools.
- Step-by-Step Milestones: Breaking the project into manageable, tangible steps, each building upon the last. This is vital for iterative development and provides clear checkpoints.
- Core Tools: Identifying the likely technologies involved.
- Potential Future Features: Listing desired add-ons to keep them in mind, even if not implemented immediately (like Jinja2, which we decided to use from the start).
The goal of this document was twofold: first, to clarify my own thinking, and second, to provide a sufficiently detailed brief for an AI coding assistant. Giving the AI a clear roadmap is far more effective than vague instructions.
The Seed Document / Initial Prompt
Here is the exact document I prepared in VS Code and then fed into the AI assistant (specifically, Google's AI model via the Cursor editor) to initiate the project:
```markdown Summary of the SSG Goals:
The objective is to build a lightweight, personal SSG using Python and Git. This system will allow you to:
- Write content locally using Markdown in VS Code.
- Organize content logically within a folder structure.
- Automate the conversion of Markdown files into complete HTML pages using a defined template.
- Generate a static website structure (HTML, CSS, potentially JS, images) in a designated output folder.
- Preview the generated site locally using a simple Python web server.
- Leverage Git for version control of content and code, with the future possibility of triggering deployment.
The core philosophy is simplicity, developer control, and using familiar tools.
Step-by-Step Implementation Plan with Motivational Milestones:
This plan breaks down the development into manageable stages, each providing a visible, working result.
Milestone 1: The Simplest Possible Conversion
- Goal: Prove the core concept: convert one Markdown file into one basic HTML file.
- Steps:
- Project Setup: Create a root folder (e.g.,
my_blog_ssg). Inside, createcontent/(for Markdown),output/(for generated HTML), andgenerate.py(your main script).- Sample Content: Place a simple
hello.mdfile incontent/with basic Markdown (heading, paragraph).- Install Dependency:
pip install markdown- Core Script Logic (
generate.py):
- Import
markdown.- Read the content of
content/hello.md.- Convert Markdown content to HTML using
markdown.markdown().- Write the resulting HTML string to
output/hello.html.- Run & Verify: Execute
python generate.py. Check thatoutput/hello.htmlexists and contains the rendered HTML.- Tangible Result: You have a script that transforms a specific Markdown file into a raw HTML file. This validates the core conversion mechanism.
Milestone 2: Basic Templating
- Goal: Wrap the generated HTML content within a consistent site structure (header, footer, etc.).
- Steps:
- Create Template: Create
template.htmlin the root directory with basic HTML5 structure (<!DOCTYPE>,<html>,<head>,<body>). Include a placeholder like{{content}}where the Markdown HTML should go. Add a basic<title>.- Update Script (
generate.py):
- Read the content of
template.html.- Perform the Markdown-to-HTML conversion as before.
- Replace the
{{content}}placeholder in the template string with the generated HTML.- Write the complete templated HTML to
output/hello.html.- Run & Verify: Execute
python generate.py. Openoutput/hello.htmldirectly in your browser (or using VS Code Live Server on theoutputfolder).- Tangible Result: Your single rendered Markdown file now looks like a proper webpage within a consistent layout.
Milestone 3: Processing Multiple Files & Basic Structure
- Goal: Automatically find and process all
.mdfiles within thecontentdirectory, maintaining a similar folder structure inoutput.- Steps:
- Organize Content: Create subfolders and more
.mdfiles withincontent/(e.g.,content/posts/post1.md,content/about.md).- Update Script (
generate.py):
- Import the
osmodule.- Use
os.walk()to recursively find all.mdfiles within thecontent/directory.- For each
.mdfile found:
- Determine the corresponding output path within
output/(e.g.,content/posts/post1.md->output/posts/post1.html).- Ensure the necessary output subdirectories exist (
os.makedirs(..., exist_ok=True)).- Perform the Markdown conversion and templating as in Milestone 2.
- Save the final HTML to the calculated output path.
- Run & Verify: Execute
python generate.py. Check theoutput/directory – it should mirror the structure ofcontent/but with.htmlfiles.- Tangible Result: Your script now builds a multi-page static site structure based on your content organization.
Milestone 4: Local Preview Server & Basic Styling
- Goal: Easily preview the entire generated site locally and add minimal CSS.
- Steps:
- Create Static Assets Folder: Create
static/css/style.cssand add some simple CSS rules.- Link CSS in Template: Add
<link rel="stylesheet" href="/static/css/style.css">(adjust path if needed) inside the<head>oftemplate.html.- Update Script (
generate.py):
- Add logic to copy the entire
static/directory tooutput/static/. Theshutilmodule (shutil.copytree) is useful here. Make sure to handle potential pre-existingoutput/staticfolders (e.g., remove then copy, or usedirs_exist_ok=Truein Python 3.8+).- Local Server:
- Open your terminal.
- Navigate into the
output/directory:cd output- Run Python's built-in HTTP server:
python -m http.server(Python 3) orpython -m SimpleHTTPServer(Python 2).- Open your browser to
http://localhost:8000(or the port specified).- Run & Verify: Execute
python generate.py. Start the local server in theoutputdirectory. Browse your site locally – pages should render correctly, and basic styling should be applied.- Tangible Result: You have a styled, multi-page static website generated by your script, which you can easily browse locally like a real website.
Core Tools Recap:
- Python: For scripting the generation process.
markdownlibrary: For Markdown-to-HTML conversion.os/shutilmodules: For file system operations.- Git: For version control of your code (
generate.py,template.html) and content (content/directory).- Python's
http.server: For local preview.
Appendix: Potential Add-on Features (Post-Core Implementation)
We like the below and so please consider them all as to be part of the project even though they are not as fleshed out. Jinja2 is a good example of a templating engine that we should consider out of the gate.
- Metadata: Use YAML frontmatter...
- Index Page Generation...
- Advanced Templating (Jinja2)...
- Static Asset Handling...
- Syntax Highlighting...
- RSS Feed...
- Git Hook Deployment... ```
(Note: The full details of the appendix items were included in the actual prompt but abbreviated here for brevity in the blog post.)
The Workflow: Pair Programming with AI
With this plan loaded into Cursor, my AI-aware editor, I essentially pointed the AI (Google's model) at the document and said, "Let's get started on Milestone 1."
What followed was remarkable velocity:
- Rapid Generation: The AI immediately started scaffolding the project structure and generating the initial
generate.pyscript based on Milestone 1's steps. - Review and Refine: My role shifted primarily to reviewing the generated code, testing it (
python generate.py), verifying the output, and providing corrective feedback or asking for the next step ("Okay, looks good. Now let's implement Milestone 2 using Jinja2 instead of basic string replacement."). - Iterative Progression: We moved through the milestones rapidly. The AI handled the boilerplate and implemented the core logic for file walking (
os.walk), Markdown conversion, Jinja2 integration, frontmatter parsing (PyYAML), and asset copying (shutil). - Problem Solving: When unexpected issues arose (like ensuring relative image paths worked correctly), I described the problem, and the AI often proposed solutions (like using
BeautifulSoup4to parse and rewrite<img>tags post-conversion), which we then refined together. - Minimal Typing: I wrote very little code from scratch. Most of my interaction involved reading, testing, prompting, and occasionally tweaking the AI's output. As I mentioned, there were points where I felt I could barely keep up with the pace of generation and the need to review and integrate.
This iterative loop – Prompt -> Generate -> Test -> Refine -> Prompt Next – continued through the core features outlined in the first blog post. Features like the config file (config.yaml), specific handling for home.md, drafts/hidden posts, and even the structure of the deployment script were built using this same collaborative process, guided by the initial plan and subsequent conversational prompts.
Reflections on the Process
This experience solidified several thoughts about AI-assisted development:
- Clear Direction is Key: A well-defined plan or prompt is exponentially more effective than vague requests. The AI could "understand" the milestones and build towards them.
- Velocity Multiplier: The speed is undeniable. Tasks that would typically involve significant typing, boilerplate, and looking up library usage details were handled in seconds. This makes the ~6-hour active development time entirely plausible.
- Shifting Roles: The developer's role leans more towards architect, reviewer, and tester. Prompt engineering and the ability to clearly articulate requirements become critical skills.
- It's Still Collaboration: It wasn't magic. It required understanding the code, identifying issues, and guiding the process. The AI is a powerful tool, but it needs direction and oversight.
Conclusion
So, that's the story behind the build. The Python SSG wasn't conjured out of thin air but meticulously planned and then rapidly executed through a tight feedback loop with an AI coding assistant. It started with the "seed document" above and grew through guided, iterative development. For solo projects or rapid prototyping, this approach proved incredibly effective, turning a multi-day project into something achievable in just a few focused hours.
Wait there's more.
Here's the really interesting part. I used an AI to generate the seed document!