Project Spec: RegionalPestGuide Programmatic Content Expansion

Project Spec: RegionalPestGuide Programmatic Content Expansion

Version: 0.1 Status: Draft Author(s): Evan Maxon, Kai Approved by: Date: 2026-03-17 Repository: emaxon/regionalpestguide GitHub Project: Content Empire Tracks: Programmatic SEO expansion for regionalpestguide.com


1. Overview

1.1 Problem Statement

RegionalPestGuide currently has 11 pest pages, 8 region pages, and 29 blog posts. There are zero intersection pages (pest × region), which means the site misses thousands of high-intent long-tail search queries like “termite control southeast”, “mosquito prevention pacific northwest”, and “ant control great plains”. These intersection queries have strong commercial intent and low competition. The site also lacks 5 common household pest categories and needs more blog content to build topical authority.

The GardeningByZone sister site already uses a Python generator script (generate-plant-zone-pages.py) to programmatically create intersection pages from data files. This spec replicates that proven pattern for RegionalPestGuide: a Python script reads existing pest and region collection files, then generates unique intersection markdown pages with rich front matter and body content.

1.2 Success Criteria

  • generate-pest-region-pages.py generates 128 intersection pages (16 pests × 8 regions) in collections/_pest_regions/
  • _layouts/pest-region.html renders all intersection pages correctly in Jekyll with zero Liquid errors
  • _config.yml includes pest_regions collection with output: true
  • Existing _layouts/pest.html cross-links to all region sub-pages for that pest
  • Existing _layouts/region.html cross-links to all pest sub-pages for that region
  • 5 new pest categories added to collections/_pests/ with substantive content
  • 50 total blog posts in _posts/ (21 new), each 800+ words with affiliate links
  • bundle exec jekyll build completes with zero errors
  • All generated pages include Amazon affiliate links with tag epmlabs-20
  • All generated pages include sister site cross-links with UTM parameters

1.3 Scope

In scope:

  • Python generator script for pest × region intersection pages
  • New pest-region layout
  • Jekyll config updates for new collection
  • Cross-link additions to existing pest and region layouts
  • 5 new pest collection files
  • 21 new blog posts (reaching 50 total)
  • Amazon affiliate integration on all new pages
  • Sister site cross-linking on all new pages

Out of scope:

  • CSS/design changes beyond matching existing patterns
  • JavaScript functionality
  • New layouts for existing pest or region pages (only adding cross-link sections)
  • Analytics or tracking setup
  • Domain/hosting changes
  • Image assets or media files
  • Sitemap or robots.txt changes (handled by jekyll-sitemap plugin automatically)

2. Architecture & Technical Decisions

2.1 Tech Stack

Component Choice Notes
Site generator Jekyll (existing) Ruby gem, uses Liquid templates
Page generator Python 3.8+ Standalone script, no pip dependencies beyond stdlib
Templating Liquid Jekyll’s native template engine
CSS framework Bulma (existing) Classes like section, container, columns, box, button is-success, notification is-light is-info
Affiliate Amazon Associates Tag: epmlabs-20

2.2 Architecture Overview

regionalpestguide/
├── generate-pest-region-pages.py    # NEW — T01
├── _config.yml                      # MODIFY — T03
├── _layouts/
│   ├── pest.html                    # MODIFY — T03
│   ├── region.html                  # MODIFY — T03
│   ├── pest-region.html             # NEW — T02
│   ├── post.html                    # existing, unchanged
│   └── default.html                 # existing, unchanged
├── collections/
│   ├── _pests/
│   │   ├── ants.md                  # MODIFY — T03 (add region_pages: true)
│   │   ├── termites.md              # MODIFY — T03
│   │   ├── ... (11 existing)
│   │   ├── centipedes-millipedes.md  # NEW — T04
│   │   ├── earwigs-silverfish.md     # NEW — T04
│   │   ├── stink-bugs.md            # NEW — T04
│   │   ├── boxelder-bugs.md         # NEW — T04
│   │   └── carpet-beetles.md        # NEW — T04
│   ├── _regions/
│   │   ├── southeast.md             # MODIFY — T03 (add pest_pages: true)
│   │   └── ... (8 existing)
│   └── _pest_regions/               # NEW directory — T01
│       ├── ants-southeast.md        # Generated by script
│       ├── ants-northeast.md
│       └── ... (128 total after T04)
└── _posts/
    ├── ... (29 existing)
    └── ... (21 new — T05)

2.3 Generator Script Design

generate-pest-region-pages.py follows the proven generate-plant-zone-pages.py pattern from GardeningByZone:

  1. Discovery phase: Scan collections/_pests/*.md and collections/_regions/*.md, parse YAML front matter from each file to extract pest_id, title, emoji, region_id, states, key_pests
  2. Data lookup: For each pest × region combination, look up a PEST_REGION_DATA dictionary embedded in the script containing unique facts, seasonal activity, regional species, and prevention tips
  3. Generation phase: For each combination, write a markdown file to collections/_pest_regions/{pest_id}-{region_id}.md with complete YAML front matter and unique body content
  4. Cleanup phase: Before generating, delete all existing files in collections/_pest_regions/ to ensure idempotency

The script must be runnable with: python3 generate-pest-region-pages.py (no arguments, no pip install).

2.4 Data Shapes

Pest collection front matter (existing schema)

---
title: "Termites"
description: "Identify, prevent, and treat termite infestations..."
pest_id: "termites"
emoji: "🐜"
region_pages: true   # NEW — added by T03
---

Region collection front matter (existing schema)

---
title: "Southeast"
description: "Pest control for the Southeast US..."
region_id: "southeast"
key_pests: ['termites', 'mosquitoes', 'cockroaches', 'fire ants', 'fleas']
states: "Alabama, Florida, Georgia, Louisiana, Mississippi, North Carolina, South Carolina, Tennessee, Virginia"
pest_pages: true     # NEW — added by T03
---

Generated pest-region intersection front matter (new schema)

---
layout: pest-region
title: "Termite Control in the Southeast"
description: "How to identify, prevent, and treat termites in Alabama, Florida, Georgia, and other Southeast states. Region-specific termite control advice."
pest_id: "termites"
region_id: "southeast"
pest_name: "Termites"
region_name: "Southeast"
permalink: /pests/termites/southeast/
states: "Alabama, Florida, Georgia, Louisiana, Mississippi, North Carolina, South Carolina, Tennessee, Virginia"
key_pests: ['termites', 'mosquitoes', 'cockroaches', 'fire ants', 'fleas']
amazon_search: "termite control southeast"
---

Blog post front matter (existing schema)

---
layout: post
title: "How to Get Rid of Ants in Texas Heat"
description: "Texas-specific strategies for ant control in extreme summer heat..."
categories: [ants, pest-control]
tags: [ants, southwest, texas, summer, treatment]
date: 2026-03-18
---

2.5 Key Design Decisions

Decision Rationale
Python script (not Jekyll plugin) Matches GBZ pattern; no Ruby gem dependencies; simpler for workers
Embedded data dict in script Self-contained; no external data files to manage; unique content per combo
collections/_pest_regions/ directory Jekyll collection convention; underscore prefix required
Permalink /pests/{pest}/{region}/ Nests under existing /pests/{pest}/ URL structure for SEO
Delete-and-regenerate idempotency Simpler than diffing; ensures clean state on every run
0.md stub excluded from generation File collections/_pests/0.md is a stub/placeholder; script skips files where pest_id is missing or empty
Separate layout file Intersection pages need breadcrumb, seasonal table, and cross-links that differ from pest or region layouts

3. Standards & Quality Gates

3.1 Testing

  • Jekyll build: bundle exec jekyll build must complete with zero errors and zero Liquid warnings
  • Page count verification: After build, verify _site/pests/ contains expected intersection page directories
  • Link validation: Spot-check 5 random intersection pages for correct affiliate links, sister site links, and internal cross-links
  • Python script: python3 -c "import ast; ast.parse(open('generate-pest-region-pages.py').read())" — syntax check
  • Idempotency: Run generator twice; diff output should show zero changes on second run

3.2 Content Quality

  • Blog posts: minimum 800 words each (verified via wc -w)
  • Generated intersection pages: minimum 200 words body content per page
  • No duplicate description values across intersection pages
  • No placeholder text like “Lorem ipsum” or “TODO”
  • All Amazon links must include tag=epmlabs-20
  • All sister site links must include UTM parameters: ?utm_source=regionalpestguide&utm_medium=cross-site&utm_campaign=internal

3.3 SEO Requirements

  • Every page has unique title and description front matter
  • Permalinks follow /pests/{pest-slug}/{region-slug}/ pattern (trailing slash)
  • H1 tag matches title front matter on every page
  • Each intersection page targets a unique keyword: {pest} control {region} or {pest} in {region}

3.4 Enforcement Layers

Layer 1: Worker Self-Check (before commit)

Per-task self-check commands specified in each task section.

Layer 2: Jekyll Build

cd /path/to/regionalpestguide && bundle exec jekyll build 2>&1

Must produce zero errors. Liquid warnings about missing variables are errors — fix them.

Layer 3: Content Audit

# Verify intersection page count
ls collections/_pest_regions/*.md | wc -l   # expect 128 after T04

# Verify blog post count
ls _posts/*.md | wc -l                      # expect 50 after T05

# Verify no placeholder content
grep -rl "TODO\|Lorem\|FIXME\|placeholder" collections/_pest_regions/ _posts/ && echo "FAIL: placeholder content found" || echo "PASS"

Layer 4: PR Merge Policy

  • Human review required
  • Required reviewers: 1 (Evan)

4. Task Breakdown


T01: Pest × Region Intersection Page Generator Script

  • Template file: GardeningByZone generate-plant-zone-pages.py pattern (reads collection files, generates intersection markdown with rich front matter and unique body content)
  • Description:

    Create generate-pest-region-pages.py in the repository root. This Python 3.8+ script (stdlib only — no pip dependencies) programmatically generates intersection pages for every pest × region combination.

    Script behavior:

    1. Parse existing collections:
      • Scan collections/_pests/*.md — for each file, extract YAML front matter fields: pest_id, title, emoji. Skip any file where pest_id is missing or empty (this excludes the 0.md stub).
      • Scan collections/_regions/*.md — for each file, extract YAML front matter fields: region_id, title, states, key_pests.
      • YAML parsing: Use a simple front-matter parser (read lines between --- delimiters, use yaml.safe_load from stdlib yaml module — note: yaml is NOT stdlib. Instead, parse front matter manually by splitting on --- and extracting key-value pairs with string splitting on : . Handle YAML list syntax ['item1', 'item2'] by stripping brackets and splitting on commas).
    2. Embedded content data: The script must contain a PEST_REGION_DATA dictionary with unique content for every pest × region combination. Structure:
      PEST_REGION_DATA = {
          ("termites", "southeast"): {
              "intro": "The Southeast's warm, humid climate makes it the #1 region in the US for termite damage. Subterranean and Formosan termites cause over $2 billion in damage annually across states like Florida, Georgia, and Alabama. The long warm season means termites remain active nearly year-round, with swarming events as early as February.",
              "species": [
                  "Eastern Subterranean Termite — the most common species across all Southeast states",
                  "Formosan Termite — established in Louisiana, Mississippi, Florida, and spreading northward",
                  "Drywood Termite — coastal areas of Florida, Georgia, and the Carolinas"
              ],
              "seasonal_activity": {
                  "Spring": "Peak swarming season (Feb–May); inspect foundations for mud tubes after rains",
                  "Summer": "Maximum colony activity; highest wood consumption rates; schedule professional inspections",
                  "Fall": "Continued activity in warm states; Formosan colonies still aggressive in FL/LA",
                  "Winter": "Reduced but not dormant; subterranean termites active below frost line year-round in Southeast"
              },
              "prevention_tips": [
                  "Maintain at least 6 inches between soil and wood siding — critical in humid Southeast climates",
                  "Install termite bait monitoring stations around foundation perimeter every 10 feet",
                  "Fix all moisture issues immediately — Southeast humidity accelerates wood decay that attracts termites",
                  "Schedule annual professional termite inspections — required by many Southeast home insurance policies",
                  "Remove dead trees and stumps within 20 feet of your home — common Formosan termite nesting sites"
              ],
              "facts": [
                  "Florida has the highest termite pressure of any US state, with all four major termite types present",
                  "Formosan termite colonies can contain 5-10 million individuals — 10x larger than native subterranean colonies",
                  "The Southeast accounts for over 50% of all US termite damage claims annually"
              ]
          },
          # ... entries for ALL pest × region combinations
      }
      

      Every pest × region combination must have a unique entry. For combinations where a pest is not naturally prevalent in a region, the content should still be unique and informative (e.g., “While scorpions are rare in the Northeast, the occasional Eastern Bark Scorpion can be found in southern Pennsylvania…”).

      Minimum data per entry: intro (2-4 sentences, 40+ words), species (2-3 items), seasonal_activity (4 seasons), prevention_tips (4-5 items), facts (3 items).

    3. Generate files:
      • Create collections/_pest_regions/ directory if it doesn’t exist
      • Delete all existing .md files in collections/_pest_regions/ before generating (idempotency)
      • For each pest × region combination, write collections/_pest_regions/{pest_id}-{region_id}.md with:

      Front matter:

      ---
      layout: pest-region
      title: "{Pest Name} Control in the {Region Name}"
      description: "How to identify, prevent, and treat {pest_name_lower} in {first_three_states} and other {Region Name} states. Region-specific {pest_name_lower} control advice."
      pest_id: "{pest_id}"
      region_id: "{region_id}"
      pest_name: "{Pest Name}"
      region_name: "{Region Name}"
      permalink: /pests/{pest_id}/{region_id}/
      states: "{states from region file}"
      key_pests: {key_pests list from region file}
      amazon_search: "{pest_name_lower} control {region_name_lower}"
      ---
      

      Body content (markdown): ```markdown

      {Pest Name} in the {Region Name}

      {intro from PEST_REGION_DATA}

      Seasonal Activity

      Season What to Expect
      Spring {spring text}
      Summer {summer text}
      Fall {fall text}
      Winter {winter text}

      Common {Pest Name} Species in the {Region Name}

      {bulleted list of species}

      Prevention Tips for {Region Name} Homeowners

      {numbered list of prevention tips}

      Did You Know?

      {bulleted list of facts}

      🛒 Browse {Pest Name} Control Products on Amazon


    For more regional home care advice, visit our sister sites:

    {sister site links with UTM params}

    
       Sister site links must use this format:
       ```markdown
       - [Lush Lawns](https://lushlawnsbook.com?utm_source=regionalpestguide&utm_medium=cross-site&utm_campaign=internal) — Complete lawn care guides
       - [Harvest Home Guides](https://harvesthomeguides.com?utm_source=regionalpestguide&utm_medium=cross-site&utm_campaign=internal) — Home gardening & harvest tips
       - [MowGuide](https://mowguide.com?utm_source=regionalpestguide&utm_medium=cross-site&utm_campaign=internal) — Mowing schedules & equipment reviews
       - [Gardening by Zone](https://gardeningbyzone.com?utm_source=regionalpestguide&utm_medium=cross-site&utm_campaign=internal) — Zone-specific planting guides
       - [HomeFix by Zone](https://homefixbyzone.com?utm_source=regionalpestguide&utm_medium=cross-site&utm_campaign=internal) — Regional home maintenance guides
    
    1. Output summary: After generation, print to stdout:
      Generated {N} pest-region pages in collections/_pest_regions/
      Pests: {comma-separated list}
      Regions: {comma-separated list}
      
  • Input Contract:
    • collections/_pests/*.md files exist with front matter containing pest_id and title
    • collections/_regions/*.md files exist with front matter containing region_id, title, states, key_pests
    • Script is run from the repository root directory
  • Output Contract:
    • collections/_pest_regions/ directory created (if not exists)
    • One .md file per pest × region combination: {pest_id}-{region_id}.md
    • Each file contains valid YAML front matter between --- delimiters
    • Each file contains unique body content (not identical across pages)
    • Initially 88 files (11 pests × 8 regions); 128 files after T04 adds 5 more pests
    • Stdout summary of generation results
  • Acceptance Criteria:
    • python3 generate-pest-region-pages.py runs without errors from repo root
    • ls collections/_pest_regions/*.md | wc -l outputs 88 (before T04) or 128 (after T04)
    • Every generated file has valid YAML front matter: python3 -c "import re; [print(f) for f in __import__('glob').glob('collections/_pest_regions/*.md') if '---' not in open(f).read()[:10]]" outputs nothing
    • Every generated file contains layout: pest-region in front matter
    • Every generated file contains permalink: in front matter
    • Every generated file contains tag=epmlabs-20 in body
    • Every generated file contains utm_source=regionalpestguide in body
    • No two files have identical description values: grep -h "^description:" collections/_pest_regions/*.md | sort | uniq -d | wc -l outputs 0
    • Running the script twice produces identical output: python3 generate-pest-region-pages.py && md5sum collections/_pest_regions/*.md > /tmp/run1.md5 && python3 generate-pest-region-pages.py && md5sum -c /tmp/run1.md5 (all OK)
    • 0.md stub from _pests/ does not produce any intersection pages
  • Dependencies: None (first task)
  • Complexity: XL (large embedded data dictionary with unique content for 128+ combinations)
  • Files to create:
    • generate-pest-region-pages.py
    • collections/_pest_regions/ directory (created by script)
    • 88 markdown files in collections/_pest_regions/ (128 after T04 re-run)
  • Self-check command:
    cd /Users/evanmaxon/repos/regionalpestguide && \
    python3 -c "import ast; ast.parse(open('generate-pest-region-pages.py').read())" && \
    python3 generate-pest-region-pages.py && \
    echo "--- File count ---" && \
    ls collections/_pest_regions/*.md | wc -l && \
    echo "--- Layout check ---" && \
    grep -L "layout: pest-region" collections/_pest_regions/*.md | wc -l && \
    echo "--- Affiliate check ---" && \
    grep -rL "epmlabs-20" collections/_pest_regions/ | wc -l && \
    echo "--- Duplicate description check ---" && \
    grep -h "^description:" collections/_pest_regions/*.md | sort | uniq -d | wc -l && \
    echo "--- Permalink check ---" && \
    grep -L "permalink:" collections/_pest_regions/*.md | wc -l
    

    Expected: syntax OK, file count = 88 (or 128 after T04), layout missing = 0, affiliate missing = 0, duplicate descriptions = 0, permalink missing = 0.

  • Do NOT:
    • Use any pip dependencies (no pyyaml, no jinja2 — stdlib only)
    • Generate pages for the 0.md stub pest
    • Use identical/templated body content across pages — every page must have unique intro, species, tips
    • Hard-code file paths — derive pest/region lists by scanning the collection directories
    • Leave any pest × region combination without a PEST_REGION_DATA entry (use a sensible fallback if needed, but prefer explicit entries)

T02: _layouts/pest-region.html Layout

  • Template file: _layouts/pest.html (existing — copy structure and HTML/CSS patterns)
  • Description:

    Create _layouts/pest-region.html — the layout used by all generated pest × region intersection pages. This layout extends default (via layout: default in its own front matter) and renders intersection page content with a breadcrumb, structured sections, affiliate CTAs, and cross-links.

    Full layout file content:

    ```html

    layout: default —

    Project Spec: RegionalPestGuide Programmatic Content Expansion

    📍 🐛

    States covered:

    Thanks for Subscribing!

    You’re in! 🎉

Thanks for subscribing to the Regional Pest Guide newsletter. You’ll receive:

  • Seasonal pest prevention checklists for your region
  • New article alerts when we publish guides
  • Exclusive tips not available on the blog

Check your inbox to confirm your subscription. If you don’t see our email, check your spam folder.

← Back to Home · Read the Blog

    </div>
  </div>
</div>

</div> </section>

        <hr>
        <h2>Related Blog Posts</h2>
        <ul>
        
        
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
          
        
        </ul>
        <hr>
        <h2>Shop  Control Products</h2>
        <p><a href="https://www.amazon.com/s?k=&tag=epmlabs-20" target="_blank" class="button is-success is-medium">🛒 Browse  Control Products for the  on Amazon</a></p>
        <hr>
        <h2>Explore More</h2>
        <div class="columns is-multiline">
          <div class="column is-6">
            <div class="box">
              <h3 class="title is-5">Other Regions for </h3>
              <ul>
              
              </ul>
            </div>
          </div>
          <div class="column is-6">
            <div class="box">
              <h3 class="title is-5">Other Pests in the </h3>
              <ul>
              
              </ul>
            </div>
          </div>
        </div>
        <hr>
        <div class="notification is-light is-info">
          <p><strong>🏡 More from EPM Labs:</strong></p>
          <ul>
            
            <li><a href="https://lushlawnsbook.com?utm_source=regionalpestguide&utm_medium=cross-site&utm_campaign=internal" target="_blank">Lush Lawns</a> — Complete lawn care guides</li>
            
            <li><a href="https://harvesthomeguides.com?utm_source=regionalpestguide&utm_medium=cross-site&utm_campaign=internal" target="_blank">Harvest Home Guides</a> — Home gardening & harvest tips</li>
            
            <li><a href="https://mowguide.com?utm_source=regionalpestguide&utm_medium=cross-site&utm_campaign=internal" target="_blank">MowGuide</a> — Mowing schedules & equipment reviews</li>
            
            <li><a href="https://gardeningbyzone.com?utm_source=regionalpestguide&utm_medium=cross-site&utm_campaign=internal" target="_blank">Gardening by Zone</a> — Zone-specific planting guides</li>
            
            <li><a href="https://lifestarter.com?utm_source=regionalpestguide&utm_medium=cross-site&utm_campaign=internal" target="_blank">LifeStarter</a> — Life skills & adulting guides</li>
            
            <li><a href="https://homefixbyzone.com?utm_source=regionalpestguide&utm_medium=cross-site&utm_campaign=internal" target="_blank">HomeFix by Zone</a> — Regional home maintenance guides</li>
            
          </ul>
        </div>
      </article>
    </div>
  </div>
</div>

</section>


  **Key layout features:**
  - Breadcrumb: Home → Pests → {Pest Name} → {Region Name}
  - Tags showing region and pest at a glance
  - States notification box
  - `<section class="section">
  <div class="container">
    <div class="columns is-centered">
      <div class="column is-8">
        <div class="content">
          <h1 class="title is-2">Thanks for Subscribing!</h1>
          <h2 id="youre-in-">You’re in! 🎉</h2>

<p>Thanks for subscribing to the Regional Pest Guide newsletter. You’ll receive:</p>

<ul>
  <li><strong>Seasonal pest prevention checklists</strong> for your region</li>
  <li><strong>New article alerts</strong> when we publish guides</li>
  <li><strong>Exclusive tips</strong> not available on the blog</li>
</ul>

<p>Check your inbox to confirm your subscription. If you don’t see our email, check your spam folder.</p>

<p><a href="/">← Back to Home</a> · <a href="/blog/">Read the Blog</a></p>

        </div>
      </div>
    </div>
  </div>
</section>
` renders the markdown body (intro, seasonal table, species, prevention, facts, affiliate CTA, sister links from the generated .md file)
  - Related blog posts filtered by `pest_id` or `region_id` in post tags
  - Amazon affiliate button using `page.amazon_search` (URL-encoded)
  - Cross-navigation: "Other Regions for this Pest" and "Other Pests in this Region" boxes
  - Sister site links from `site.sister_sites` config

- **Input Contract:**
  - `_layouts/default.html` exists (parent layout)
  - Generated pages have front matter with: `layout`, `title`, `description`, `pest_id`, `region_id`, `pest_name`, `region_name`, `permalink`, `states`, `amazon_search`
  - `site.sister_sites` defined in `_config.yml`
  - `site.pest_regions` collection defined in `_config.yml` (T03)
  - `site.posts` with `tags` array

- **Output Contract:**
  - `_layouts/pest-region.html` file that renders correctly in Jekyll
  - Breadcrumb with 4 levels
  - Cross-navigation boxes populated from `site.pest_regions`
  - Amazon affiliate link with `epmlabs-20` tag
  - Sister site links with UTM parameters

- **Acceptance Criteria:**
  - [ ] File exists at `_layouts/pest-region.html`
  - [ ] File starts with `---\nlayout: default\n---`
  - [ ] Contains `Project Spec: RegionalPestGuide Programmatic Content Expansion` in an `<h1>` tag
  - [ ] Contains breadcrumb `<nav>` with links to `/`, `/pests/`, and `/pests//`
  - [ ] Contains `<section class="section">
  <div class="container">
    <div class="columns is-centered">
      <div class="column is-8">
        <div class="content">
          <h1 class="title is-2">Thanks for Subscribing!</h1>
          <h2 id="youre-in-">You’re in! 🎉</h2>

<p>Thanks for subscribing to the Regional Pest Guide newsletter. You’ll receive:</p>

<ul>
  <li><strong>Seasonal pest prevention checklists</strong> for your region</li>
  <li><strong>New article alerts</strong> when we publish guides</li>
  <li><strong>Exclusive tips</strong> not available on the blog</li>
</ul>

<p>Check your inbox to confirm your subscription. If you don’t see our email, check your spam folder.</p>

<p><a href="/">← Back to Home</a> · <a href="/blog/">Read the Blog</a></p>

        </div>
      </div>
    </div>
  </div>
</section>
` to render page body
  - [ ] Contains Amazon affiliate link with `tag=epmlabs-20`
  - [ ] Contains `site.sister_sites` loop for cross-site links
  - [ ] Contains `site.pest_regions` loops for cross-navigation
  - [ ] `bundle exec jekyll build` produces zero Liquid errors referencing `pest-region` layout
  - [ ] Rendered HTML for any intersection page contains a valid `<nav class="breadcrumb">` element
  - [ ] Rendered HTML contains at least one `<a>` tag with `amazon.com` href

- **Dependencies:** T03 (needs `pest_regions` collection in `_config.yml` for `site.pest_regions` loops to work)
- **Complexity:** M
- **Files to create:**
  - `_layouts/pest-region.html`
- **Self-check command:**
  ```bash
  cd /Users/evanmaxon/repos/regionalpestguide && \
  test -f _layouts/pest-region.html && echo "PASS: file exists" || echo "FAIL: file missing" && \
  head -3 _layouts/pest-region.html | grep -q "layout: default" && echo "PASS: extends default" || echo "FAIL: no parent layout" && \
  grep -q "page.title" _layouts/pest-region.html && echo "PASS: uses page.title" || echo "FAIL: missing title" && \
  grep -q "epmlabs-20" _layouts/pest-region.html && echo "PASS: affiliate tag" || echo "FAIL: no affiliate tag" && \
  grep -q "site.pest_regions" _layouts/pest-region.html && echo "PASS: cross-nav" || echo "FAIL: no cross-nav" && \
  grep -q "site.sister_sites" _layouts/pest-region.html && echo "PASS: sister sites" || echo "FAIL: no sister sites"
  • Do NOT:
    • Create a standalone HTML file — it must extend default layout
    • Use inline CSS — use existing Bulma classes
    • Hard-code pest or region names — all content must come from page.* or site.* variables
    • Omit the `<section class="section">

    Thanks for Subscribing!

    You’re in! 🎉

Thanks for subscribing to the Regional Pest Guide newsletter. You’ll receive:

  • Seasonal pest prevention checklists for your region
  • New article alerts when we publish guides
  • Exclusive tips not available on the blog

Check your inbox to confirm your subscription. If you don’t see our email, check your spam folder.

← Back to Home · Read the Blog

    </div>
  </div>
</div>

</div> </section> ` tag — the generated markdown body must render

  • Use Liquid syntax that requires plugins beyond jekyll-sitemap and jekyll-seo-tag

T03: Jekyll Config + Navigation Updates

  • Template file: _config.yml (existing), _layouts/pest.html (existing), _layouts/region.html (existing)
  • Description:

    Three changes required:

    1. Add pest_regions collection to _config.yml:

    Add pest_regions to the existing collections: block:

    collections:
      pests:
        output: true
        permalink: /pests/:slug/
      regions:
        output: true
        permalink: /regions/:slug/
      pest_regions:
        output: true
        permalink: /pests/:path/
    

    Add default layout for pest_regions in the defaults: block:

    - scope:
        path: ""
        type: "pest_regions"
      values:
        layout: "pest-region"
    

    2. Update pest collection files — add region_pages: true:

    For every file in collections/_pests/*.md (except 0.md), add region_pages: true to the YAML front matter. This flag is used by the updated pest.html layout to conditionally show the region cross-links section.

    Example — collections/_pests/termites.md front matter becomes:

    ---
    title: "Termites"
    description: "Identify, prevent, and treat termite infestations in your home with region-specific advice."
    pest_id: "termites"
    emoji: "🐜"
    region_pages: true
    ---
    

    3. Update region collection files — add pest_pages: true:

    For every file in collections/_regions/*.md, add pest_pages: true to the YAML front matter.

    Example — collections/_regions/southeast.md front matter becomes:

    ---
    title: "Southeast"
    description: "Pest control for the Southeast US  hot, humid climates mean year-round pest pressure."
    region_id: "southeast"
    key_pests: ['termites', 'mosquitoes', 'cockroaches', 'fire ants', 'fleas']
    states: "Alabama, Florida, Georgia, Louisiana, Mississippi, North Carolina, South Carolina, Tennessee, Virginia"
    pest_pages: true
    ---
    

    4. Add cross-links section to _layouts/pest.html:

    Insert the following block before the closing </article> tag, after the existing sister sites <div class="notification"> block:

      
    

    5. Add cross-links section to _layouts/region.html:

    Insert the following block before the closing </article> tag, after the existing “Browse by Pest” section:

      
    
  • Input Contract:
    • _config.yml exists with collections: and defaults: blocks
    • _layouts/pest.html exists with the structure shown in §2.2
    • _layouts/region.html exists with the structure shown in §2.2
    • All pest collection files have pest_id in front matter
    • All region collection files have region_id in front matter
  • Output Contract:
    • _config.yml includes pest_regions collection with output: true and permalink: /pests/:path/
    • _config.yml includes default layout pest-region for pest_regions type
    • All pest files (except 0.md) have region_pages: true in front matter
    • All region files have pest_pages: true in front matter
    • _layouts/pest.html contains conditional region cross-links block
    • _layouts/region.html contains conditional pest cross-links block
  • Acceptance Criteria:
    • grep -A2 "pest_regions:" _config.yml shows output: true and permalink: /pests/:path/
    • grep "type: \"pest_regions\"" _config.yml OR grep 'type: "pest_regions"' _config.yml OR grep "type: pest_regions" _config.yml returns a match (default scope entry exists)
    • grep -L "region_pages: true" collections/_pests/*.md outputs only collections/_pests/0.md
    • grep -L "pest_pages: true" collections/_regions/*.md outputs nothing (all regions updated)
    • grep -q "site.pest_regions" _layouts/pest.html && echo "PASS" outputs PASS
    • grep -q "site.pest_regions" _layouts/region.html && echo "PASS" outputs PASS
    • bundle exec jekyll build completes with zero errors
    • Existing pest page URLs unchanged (still /pests/{slug}/)
    • Existing region page URLs unchanged (still /regions/{slug}/)
  • Dependencies: None (can run in parallel with T01; T02 depends on this for site.pest_regions variable)
  • Complexity: M
  • Files to modify:
    • _config.yml
    • _layouts/pest.html
    • _layouts/region.html
    • collections/_pests/ants.md
    • collections/_pests/bed-bugs.md
    • collections/_pests/cockroaches.md
    • collections/_pests/fleas.md
    • collections/_pests/mosquitoes.md
    • collections/_pests/rodents.md
    • collections/_pests/spiders.md
    • collections/_pests/termites.md
    • collections/_pests/ticks.md
    • collections/_pests/wasps.md
    • collections/_regions/great-plains.md
    • collections/_regions/midwest.md
    • collections/_regions/mountain-west.md
    • collections/_regions/northeast.md
    • collections/_regions/pacific-northwest.md
    • collections/_regions/southeast.md
    • collections/_regions/southwest.md
    • collections/_regions/west-coast.md
  • Self-check command:
    cd /Users/evanmaxon/repos/regionalpestguide && \
    grep "pest_regions:" _config.yml && echo "PASS: collection defined" && \
    grep -c "region_pages: true" collections/_pests/*.md && \
    grep -c "pest_pages: true" collections/_regions/*.md && \
    grep -q "site.pest_regions" _layouts/pest.html && echo "PASS: pest layout cross-links" && \
    grep -q "site.pest_regions" _layouts/region.html && echo "PASS: region layout cross-links"
    
  • Do NOT:
    • Remove or reorder existing collections: entries
    • Change existing permalink patterns for pests or regions
    • Modify body content of pest or region collection files (only add front matter key)
    • Break existing pest.html or region.html layout functionality
    • Add the cross-links block to 0.md

T04: 5 New Pest Categories

  • Template file: collections/_pests/termites.md (existing — follow same front matter schema and body content structure)
  • Description:

    Add 5 new pest collection files to collections/_pests/. Each file must follow the exact front matter schema of existing pest files and include substantive body content covering identification, prevention, treatment, and an Amazon affiliate product link.

    Files to create:

    1. collections/_pests/centipedes-millipedes.md

    ---
    title: "Centipedes & Millipedes"
    description: "Identify, prevent, and control centipede and millipede infestations in your home with region-specific advice."
    pest_id: "centipedes-millipedes"
    emoji: "🐛"
    region_pages: true
    ---
    

    Body content must cover: house centipedes vs outdoor species, millipede vs centipede differences, moisture-driven entry, basement/bathroom hotspots, exclusion methods, dehumidifier recommendation, Amazon product CTA, and sister site cross-links. Minimum 300 words.

    2. collections/_pests/earwigs-silverfish.md

    ---
    title: "Earwigs & Silverfish"
    description: "Identify, prevent, and control earwig and silverfish infestations in your home with region-specific advice."
    pest_id: "earwigs-silverfish"
    emoji: "🪲"
    region_pages: true
    ---
    

    Body content must cover: earwig identification (forceps/pincers), silverfish identification (teardrop shape, silver scales), moisture requirements, paper/fabric damage from silverfish, garden damage from earwigs, trapping methods, Amazon product CTA, and sister site cross-links. Minimum 300 words.

    3. collections/_pests/stink-bugs.md

    ---
    title: "Stink Bugs"
    description: "Identify, prevent, and control stink bug infestations in your home with region-specific advice."
    pest_id: "stink-bugs"
    emoji: "🪲"
    region_pages: true
    ---
    

    Body content must cover: brown marmorated stink bug (BMSB) as invasive species, shield-shaped identification, fall home invasion behavior, overwintering in walls/attics, why not to crush them (odor), vacuum removal method, exclusion sealing, Amazon product CTA, and sister site cross-links. Minimum 300 words.

    4. collections/_pests/boxelder-bugs.md

    ---
    title: "Boxelder Bugs"
    description: "Identify, prevent, and control boxelder bug infestations in your home with region-specific advice."
    pest_id: "boxelder-bugs"
    emoji: "🐞"
    region_pages: true
    ---
    

    Body content must cover: black and red/orange coloring identification, association with boxelder/maple/ash trees, fall congregating behavior on sunny walls, overwintering indoors, nuisance (not structural damage), tree removal as long-term solution, sealing entry points, Amazon product CTA, and sister site cross-links. Minimum 300 words.

    5. collections/_pests/carpet-beetles.md

    ---
    title: "Carpet Beetles"
    description: "Identify, prevent, and control carpet beetle infestations in your home with region-specific advice."
    pest_id: "carpet-beetles"
    emoji: "🪲"
    region_pages: true
    ---
    

    Body content must cover: varied carpet beetle, black carpet beetle, furniture carpet beetle species, larval damage to natural fibers (wool, silk, leather), adult beetles attracted to light/flowers, signs of infestation (shed larval skins, irregular holes in fabric), thorough vacuuming as primary control, Amazon product CTA, and sister site cross-links. Minimum 300 words.

    After creating all 5 files, re-run python3 generate-pest-region-pages.py to generate 40 new intersection pages (5 new pests × 8 regions), bringing the total to 128.

    ⚠️ IMPORTANT: Before re-running the generator, the worker executing T01 must have already added entries for all 5 new pests × 8 regions (40 new entries) to the PEST_REGION_DATA dictionary. If T01 and T04 are done by different workers, T04 worker must update the generator script to add these 40 entries before re-running.

  • Input Contract:
    • Existing pest files in collections/_pests/ for schema reference
    • generate-pest-region-pages.py from T01 already created
  • Output Contract:
    • 5 new .md files in collections/_pests/
    • Each with valid front matter matching existing schema plus region_pages: true
    • Each with 300+ words of body content
    • Each with Amazon affiliate link containing tag=epmlabs-20
    • Each with sister site cross-links with UTM parameters
    • After re-running generator: 128 total files in collections/_pest_regions/
  • Acceptance Criteria:
    • ls collections/_pests/*.md | wc -l outputs 16 (11 existing + 5 new)
    • Each new file contains pest_id:, title:, description:, emoji:, region_pages: true in front matter
    • Each new file contains epmlabs-20 in body
    • Each new file contains utm_source=regionalpestguide in body
    • Each new file body is 300+ words: for f in centipedes-millipedes earwigs-silverfish stink-bugs boxelder-bugs carpet-beetles; do echo "$f: $(wc -w < collections/_pests/$f.md) words"; done
    • python3 generate-pest-region-pages.py re-runs without error
    • ls collections/_pest_regions/*.md | wc -l outputs 128
    • bundle exec jekyll build completes with zero errors
  • Dependencies: T01 (generator script must exist), T03 (region_pages: true schema established)
  • Complexity: L
  • Files to create:
    • collections/_pests/centipedes-millipedes.md
    • collections/_pests/earwigs-silverfish.md
    • collections/_pests/stink-bugs.md
    • collections/_pests/boxelder-bugs.md
    • collections/_pests/carpet-beetles.md
  • Files to modify:
    • generate-pest-region-pages.py (add 40 new PEST_REGION_DATA entries for new pests × all regions)
  • Self-check command:
    cd /Users/evanmaxon/repos/regionalpestguide && \
    for f in centipedes-millipedes earwigs-silverfish stink-bugs boxelder-bugs carpet-beetles; do \
      test -f "collections/_pests/$f.md" && echo "PASS: $f exists" || echo "FAIL: $f missing"; \
      grep -q "pest_id:" "collections/_pests/$f.md" && echo "PASS: $f has pest_id" || echo "FAIL: $f no pest_id"; \
      grep -q "region_pages: true" "collections/_pests/$f.md" && echo "PASS: $f has region_pages" || echo "FAIL: $f no region_pages"; \
      grep -q "epmlabs-20" "collections/_pests/$f.md" && echo "PASS: $f has affiliate" || echo "FAIL: $f no affiliate"; \
    done && \
    python3 generate-pest-region-pages.py && \
    echo "Total pest-region pages: $(ls collections/_pest_regions/*.md | wc -l)"
    
  • Do NOT:
    • Modify existing pest collection files (those are handled in T03)
    • Use placeholder body content — each pest must have real, informative content
    • Forget the region_pages: true flag (needed for cross-links in pest.html)
    • Skip the generator re-run after adding new pests

T05: Blog Expansion to 50 Posts

  • Template file: _posts/2025-12-01-how-to-identify-termites-by-region.md (existing — follow same front matter schema and content quality)
  • Description:

    Add 21 new blog posts to _posts/ to bring the total from 29 to 50. Each post targets a long-tail search query combining a pest type with a region or seasonal context. Posts must be substantive (800+ words), include Amazon affiliate links, include sister site cross-links, and be tagged with relevant pest_id values so they appear in the “Related Blog Posts” sections of pest and intersection pages.

    Date spread: Posts should be dated across 4 weeks starting 2026-03-18, approximately 5 posts per week (Mon–Fri). Use this schedule:

    # Date Filename Title Target Keyword Tags (must include)
    1 2026-03-18 2026-03-18-how-to-get-rid-of-ants-in-texas-heat.md “How to Get Rid of Ants in Texas Heat” ants texas summer control [ants, southwest, texas, summer]
    2 2026-03-19 2026-03-19-mosquito-control-pacific-northwest.md “Mosquito Control in the Pacific Northwest” mosquito control pacific northwest [mosquitoes, pacific-northwest, prevention]
    3 2026-03-20 2026-03-20-termites-in-southeast-winter.md “Do Termites Stay Active in Southeast Winters?” termites southeast winter activity [termites, southeast, winter, seasonal]
    4 2026-03-21 2026-03-21-cockroach-prevention-apartment-living.md “Cockroach Prevention for Apartment Living” cockroach prevention apartment [cockroaches, prevention, apartment]
    5 2026-03-22 2026-03-22-tick-removal-and-prevention-northeast.md “Tick Removal and Prevention in the Northeast” tick prevention northeast lyme [ticks, northeast, prevention, lyme]
    6 2026-03-25 2026-03-25-best-spider-repellents-for-basements.md “Best Spider Repellents for Basements” spider repellent basement [spiders, prevention, products]
    7 2026-03-26 2026-03-26-rodent-control-in-midwest-farmhouses.md “Rodent Control in Midwest Farmhouses” rodent control midwest farm [rodents, midwest, farmhouse, exclusion]
    8 2026-03-27 2026-03-27-flea-control-for-dogs-and-cats.md “Flea Control for Dogs and Cats: A Complete Guide” flea control dogs cats pets [fleas, pets, treatment, prevention]
    9 2026-03-28 2026-03-28-wasp-nest-removal-safely.md “How to Remove a Wasp Nest Safely” wasp nest removal safe [wasps, removal, safety, diy]
    10 2026-03-29 2026-03-29-bed-bug-signs-hotel-travel.md “Bed Bug Signs Every Hotel Traveler Should Know” bed bug signs hotel travel [bed-bugs, travel, identification, hotel]
    11 2026-04-01 2026-04-01-stink-bug-invasion-fall-prevention.md “Stink Bug Fall Invasion: How to Keep Them Out” stink bug fall prevention [stink-bugs, fall, prevention, exclusion]
    12 2026-04-02 2026-04-02-carpet-beetle-damage-wool-clothing.md “Carpet Beetle Damage: Protecting Your Wool and Fabrics” carpet beetle wool damage [carpet-beetles, prevention, identification]
    13 2026-04-03 2026-04-03-mosquito-borne-diseases-southeast.md “Mosquito-Borne Diseases in the Southeast US” mosquito diseases southeast [mosquitoes, southeast, health, diseases]
    14 2026-04-04 2026-04-04-ant-control-great-plains-farms.md “Ant Control for Great Plains Farms and Homesteads” ant control great plains [ants, great-plains, agriculture, outdoor]
    15 2026-04-05 2026-04-05-scorpion-proofing-your-arizona-home.md “Scorpion-Proofing Your Arizona Home” scorpion proofing arizona [spiders, southwest, arizona, exclusion]
    16 2026-04-08 2026-04-08-centipede-vs-millipede-identification.md “Centipede vs Millipede: Identification and Control” centipede millipede identification [centipedes-millipedes, identification]
    17 2026-04-09 2026-04-09-termite-swarm-season-what-to-do.md “Termite Swarm Season: What to Do When You See Swarmers” termite swarm season [termites, spring, identification, swarm]
    18 2026-04-10 2026-04-10-boxelder-bugs-why-on-my-house.md “Boxelder Bugs: Why They’re All Over Your House” boxelder bugs house fall [boxelder-bugs, fall, identification]
    19 2026-04-11 2026-04-11-diy-vs-professional-pest-control.md “DIY vs Professional Pest Control: When to Call an Expert” diy vs professional pest control [pest-control, professional, diy, cost]
    20 2026-04-12 2026-04-12-rodent-proof-your-mountain-cabin.md “How to Rodent-Proof Your Mountain Cabin” rodent proof mountain cabin [rodents, mountain-west, exclusion, cabin]
    21 2026-04-13 2026-04-13-earwig-silverfish-bathroom-guide.md “Earwigs and Silverfish in Your Bathroom: Causes and Solutions” earwig silverfish bathroom [earwigs-silverfish, bathroom, moisture]

    Content requirements for every post:

    • Front matter: layout: post, title, description (unique, 120-160 chars), categories (array), tags (array — must include the relevant pest_id so Related Blog Posts sections pick it up), date
    • Body: 800+ words of substantive, original content
    • At least 2 Amazon affiliate links with tag=epmlabs-20 (product recommendations woven into content)
    • One sister site cross-link in a closing paragraph with UTM parameters
    • H2 headers for structure (at least 4 H2 sections per post)
    • No filler/placeholder text
  • Input Contract:
    • Existing posts in _posts/ for schema and style reference
    • 29 existing posts present
  • Output Contract:
    • 21 new .md files in _posts/
    • Each following the naming convention: YYYY-MM-DD-slug.md
    • Each with valid front matter matching existing post schema
    • Each with 800+ words of body content
    • Each with Amazon affiliate links containing tag=epmlabs-20
    • Each with sister site cross-link containing UTM parameters
    • Total post count: 50
  • Acceptance Criteria:
    • ls _posts/*.md | wc -l outputs 50
    • Every new post has layout: post in front matter
    • Every new post has tags: in front matter
    • Every new post body is 800+ words: for f in _posts/2026-03-18*.md _posts/2026-03-19*.md _posts/2026-03-2*.md _posts/2026-04-*.md; do wc -w < "$f"; done | awk '$1 < 800 {print "FAIL: under 800 words"; exit 1}'
    • Every new post contains epmlabs-20: for f in _posts/2026-03-18*.md _posts/2026-03-19*.md _posts/2026-03-2[0-9]*.md _posts/2026-04-*.md; do grep -qL "epmlabs-20" "$f" && echo "FAIL: $f missing affiliate"; done
    • Every new post contains utm_source=regionalpestguide: grep -rL "utm_source=regionalpestguide" _posts/2026-03-18* _posts/2026-03-19* _posts/2026-03-2[0-9]* _posts/2026-04-* | wc -l outputs 0
    • No duplicate titles: grep -h "^title:" _posts/*.md | sort | uniq -d | wc -l outputs 0
    • bundle exec jekyll build completes with zero errors
  • Dependencies: None (can run in parallel with T01-T04; references new pest_ids in tags for T04 posts)
  • Complexity: XL (21 posts × 800+ words = 16,800+ words of unique content)
  • Files to create:
    • _posts/2026-03-18-how-to-get-rid-of-ants-in-texas-heat.md
    • _posts/2026-03-19-mosquito-control-pacific-northwest.md
    • _posts/2026-03-20-termites-in-southeast-winter.md
    • _posts/2026-03-21-cockroach-prevention-apartment-living.md
    • _posts/2026-03-22-tick-removal-and-prevention-northeast.md
    • _posts/2026-03-25-best-spider-repellents-for-basements.md
    • _posts/2026-03-26-rodent-control-in-midwest-farmhouses.md
    • _posts/2026-03-27-flea-control-for-dogs-and-cats.md
    • _posts/2026-03-28-wasp-nest-removal-safely.md
    • _posts/2026-03-29-bed-bug-signs-hotel-travel.md
    • _posts/2026-04-01-stink-bug-invasion-fall-prevention.md
    • _posts/2026-04-02-carpet-beetle-damage-wool-clothing.md
    • _posts/2026-04-03-mosquito-borne-diseases-southeast.md
    • _posts/2026-04-04-ant-control-great-plains-farms.md
    • _posts/2026-04-05-scorpion-proofing-your-arizona-home.md
    • _posts/2026-04-08-centipede-vs-millipede-identification.md
    • _posts/2026-04-09-termite-swarm-season-what-to-do.md
    • _posts/2026-04-10-boxelder-bugs-why-on-my-house.md
    • _posts/2026-04-11-diy-vs-professional-pest-control.md
    • _posts/2026-04-12-rodent-proof-your-mountain-cabin.md
    • _posts/2026-04-13-earwig-silverfish-bathroom-guide.md
  • Self-check command:
    cd /Users/evanmaxon/repos/regionalpestguide && \
    echo "Total posts: $(ls _posts/*.md | wc -l)" && \
    echo "--- Word count check (new posts) ---" && \
    for f in _posts/2026-03-1[89]*.md _posts/2026-03-2*.md _posts/2026-04-*.md; do \
      words=$(wc -w < "$f" 2>/dev/null || echo 0); \
      if [ "$words" -lt 800 ]; then echo "FAIL: $(basename $f) = $words words"; fi; \
    done && \
    echo "--- Affiliate check ---" && \
    grep -rL "epmlabs-20" _posts/2026-03-1[89]*.md _posts/2026-03-2*.md _posts/2026-04-*.md 2>/dev/null | wc -l && \
    echo "--- Duplicate title check ---" && \
    grep -h "^title:" _posts/*.md | sort | uniq -d | wc -l
    
  • Do NOT:
    • Modify existing blog posts
    • Use placeholder or filler content — every post must be substantive and informative
    • Use identical structures across posts — vary the format (some listicles, some guides, some Q&A)
    • Forget to include pest_id values in tags array (critical for Related Blog Posts filtering)
    • Use future dates beyond 2026-04-13

5. Dependency Graph

T01 (Generator Script) ──────┐
                              ├──→ T04 (New Pests) ──→ Re-run generator
T03 (Config + Navigation) ───┤
                              ├──→ T02 (Layout)
                              │
T05 (Blog Posts) ─────────────┘ (independent, can run in parallel)

Execution order:

  1. Phase 1 (parallel): T01 + T03 + T05 — no inter-dependencies
  2. Phase 2 (after T01 + T03): T02 — needs pest_regions collection from T03
  3. Phase 3 (after T01 + T03): T04 — needs generator from T01 and region_pages pattern from T03
  4. Final validation: bundle exec jekyll build after all tasks complete

Critical path: T01 → T04 → build validation


6. Risks & Mitigations

Risk Impact Likelihood Mitigation
YAML parsing without PyYAML Generator script may fail on edge cases Medium Use simple key-value extraction; test against all existing files; handle single-quoted lists
128 intersection pages slow Jekyll build Build time increases significantly Low Jekyll handles 200+ pages fine; monitor build time
Duplicate content flags from search engines SEO penalty for thin/similar pages Medium Every page must have unique intro, species, facts; minimum 200 words unique body content per page
Liquid template errors in new layout Build failures Low Test layout with minimal front matter first; validate all page.* variables exist
Generator script data dict becomes unwieldy 128+ entries in a single Python file Medium Organize PEST_REGION_DATA dict alphabetically by key tuple; add comments for each section
Blog post quality at scale 21 posts × 800+ words risks thin content Medium Each post targets a specific long-tail query; require 4+ H2 sections; verify word count in self-check
Amazon affiliate links break Revenue loss Low Use search URLs (not product-specific ASINs) — resilient to product changes

7. Open Questions

# Question Impact Default if unresolved
Q1 Should intersection pages include structured data (JSON-LD) for SEO? Better search appearance No — defer to future enhancement
Q2 Should the generator script also create a sitemap entry or rely on jekyll-sitemap? SEO completeness Rely on jekyll-sitemap plugin (already configured)
Q3 Should intersection pages have Open Graph / social meta tags? Social sharing Rely on jekyll-seo-tag plugin (already configured)
Q4 Should we add region-specific key_pests data for the 5 new pest categories to region files? Region accuracy No — existing region key_pests arrays are fine; new pests get intersection pages regardless
Q5 Should the 0.md stub in _pests/ be deleted? Cleanliness No — leave it; generator skips it

8. Glossary

Term Definition
Intersection page A page targeting a specific pest + region combination (e.g., “Termite Control in the Southeast”)
pest_id URL-safe slug identifier for a pest (e.g., termites, bed-bugs, centipedes-millipedes)
region_id URL-safe slug identifier for a region (e.g., southeast, pacific-northwest)
PEST_REGION_DATA Python dictionary in the generator script containing unique content for each pest × region combination
Sister site Other EPM Labs content sites that cross-link for SEO value (Lush Lawns, Harvest Home Guides, MowGuide, Gardening by Zone, HomeFix by Zone, LifeStarter)
UTM parameters URL parameters for tracking cross-site traffic (utm_source, utm_medium, utm_campaign)
Affiliate tag Amazon Associates tracking tag (epmlabs-20) appended to all Amazon links
Collection Jekyll content type with its own directory, layout defaults, and output settings
Programmatic SEO Strategy of generating many targeted pages algorithmically to capture long-tail search queries
GBZ Gardening by Zone — sister site with the template generator pattern this spec follows
Idempotent Running the generator multiple times produces the same output (delete-and-regenerate pattern)
Bulma CSS framework used by the Jekyll site for layout and component styling

_Template version: autopilot/v0.4 Spec version: 0.1_