Complete Export Documentation

This document describes the Ruby script that exports the entire Field Guide to a single hierarchical Markdown file optimized for LLM ingestion.

Overview

The export process uses a Ruby script (export_fieldguide.rb) instead of Jekyll’s Liquid templating to generate a clean, hierarchical Markdown export. This approach provides:

File Location

Script: export_fieldguide.rb (in repository root)

Output: exports/FIELDGUIDE_all.md

Running the Export

VS Code

  1. Press Cmd+Shift+P / Ctrl+Shift+P
  2. Select “Tasks: Run Task”
  3. Choose “Export Field Guide to Markdown (Ruby Script)”

Command Line

ruby export_fieldguide.rb

Export Structure

The script generates a hierarchical Markdown document following the navigation structure defined in _data/nav.yml:

# Section (e.g., Catalytic Funding)

## Group (e.g., Making Decisions)

### Page (e.g., Application Intake)

#### Content Section (from page's ## heading)

##### Content Subsection (from page's ### heading)

Hierarchy Levels

How It Works

1. Load Navigation Structure

Reads _data/nav.yml to determine the order and hierarchy of content:

nav = YAML.load_file('_data/nav.yml')

2. Find Markdown Files

For each page title in the navigation, the script searches for matching files using context-aware lookup:

This context-aware approach prevents filename collisions (e.g., catalytic-funding/planning-preparing/fundraising.md vs community-building/experiences/fundraising.md)

3. Parse Frontmatter and Read Page Content

Parses YAML frontmatter to extract metadata (layout type, subtitle, etc.):

frontmatter = parse_frontmatter(file)
# Returns hash with frontmatter fields: layout, subtitle, experience, etc.

Reads the markdown file and strips YAML frontmatter:

content = File.read(file)
if content.start_with?('---')
  parts = content.split(/^---\s*$/, 3)
  content = parts[2] || ""
end

If a subtitle is present in frontmatter, it’s rendered in bold immediately after the page heading:

### Page Title

**This is the subtitle from frontmatter**

Page content begins here...

4. Clean Up Liquid Tags

Removes or transforms Liquid template tags for clean markdown output:

Thinking Questions

Input:


<div class="alert alert-secondary bd-thinking-questions">
<h5 id="thinking-questions">Thinking Questions</h5>

<ul>
  <li>Question 1</li>
  <li>Question 2</li>
</ul>
</div>

Output:

##### Thinking Questions

* Question 1
* Question 2

Examples

Input:


<div class="card" id="example-example-title">
  <div class="card-header">
    <em>Example Title</em>
  </div>
  <div class="card-body">
<p>Content here…</p>
</div>
</div>

Output:

> **_Example Title_**
>
> Content here...

Checklists

Input:

<div class="row">
  <div class="col-6">
    <div class="list-group" id="checklist-catalytic-funding_application-components-items" role="tablist"><a class="list-group-item list-group-item-action" data-toggle="list" role="tab"
          id="checklist-catalytic-funding_application-components-applicant-contact-information-list"
          href="#checklist-catalytic-funding_application-components-applicant-contact-information"
          aria-controls="applicant-contact-information"
          style="padding-left: 3rem;"
        ><i class="fas fa-check-square" style="margin-left: -1.75rem; margin-right: .85rem;"></i>Applicant Contact Information</a><a class="list-group-item list-group-item-action" data-toggle="list" role="tab"
          id="checklist-catalytic-funding_application-components-organizational-information-list"
          href="#checklist-catalytic-funding_application-components-organizational-information"
          aria-controls="organizational-information"
          style="padding-left: 3rem;"
        ><i class="fas fa-check-square" style="margin-left: -1.75rem; margin-right: .85rem;"></i>Organizational Information</a><a class="list-group-item list-group-item-action" data-toggle="list" role="tab"
          id="checklist-catalytic-funding_application-components-narrative-questions-that-align-with-decisionmaking-criteria-list"
          href="#checklist-catalytic-funding_application-components-narrative-questions-that-align-with-decisionmaking-criteria"
          aria-controls="narrative-questions-that-align-with-decisionmaking-criteria"
          style="padding-left: 3rem;"
        ><i class="fas fa-check-square" style="margin-left: -1.75rem; margin-right: .85rem;"></i>Narrative Questions that align with Decisionmaking Criteria</a><a class="list-group-item list-group-item-action" data-toggle="list" role="tab"
          id="checklist-catalytic-funding_application-components-budget-list"
          href="#checklist-catalytic-funding_application-components-budget"
          aria-controls="budget"
          style="padding-left: 3rem;"
        ><i class="fas fa-check-square" style="margin-left: -1.75rem; margin-right: .85rem;"></i>Budget</a><a class="list-group-item list-group-item-action" data-toggle="list" role="tab"
          id="checklist-catalytic-funding_application-components-timeline-list"
          href="#checklist-catalytic-funding_application-components-timeline"
          aria-controls="timeline"
          style="padding-left: 3rem;"
        ><i class="fas fa-check-square" style="margin-left: -1.75rem; margin-right: .85rem;"></i>Timeline</a><a class="list-group-item list-group-item-action" data-toggle="list" role="tab"
          id="checklist-catalytic-funding_application-components-references-and-or-letters-of-support-list"
          href="#checklist-catalytic-funding_application-components-references-and-or-letters-of-support"
          aria-controls="references-and-or-letters-of-support"
          style="padding-left: 3rem;"
        ><i class="fas fa-check-square" style="margin-left: -1.75rem; margin-right: .85rem;"></i>References and/or Letters of Support</a><a class="list-group-item list-group-item-action" data-toggle="list" role="tab"
          id="checklist-catalytic-funding_application-components-terms-and-conditions-list"
          href="#checklist-catalytic-funding_application-components-terms-and-conditions"
          aria-controls="terms-and-conditions"
          style="padding-left: 3rem;"
        ><i class="fas fa-check-square" style="margin-left: -1.75rem; margin-right: .85rem;"></i>Terms and Conditions</a></div>
  </div>
  <div class="col-6">
    <div class="tab-content" id="checklist-catalytic-funding_application-components-tabs"><div class="tab-pane fade" role="tabpanel"
            id="checklist-catalytic-funding_application-components-applicant-contact-information"
            aria-labelledby="checklist-catalytic-funding_application-components-applicant-contact-information-list"
          ><div class="alert alert-secondary" role="alert">Name, daytime phone, email address, social media for person completing the application who should receive follow-up</div></div><div class="tab-pane fade" role="tabpanel"
            id="checklist-catalytic-funding_application-components-organizational-information"
            aria-labelledby="checklist-catalytic-funding_application-components-organizational-information-list"
          ><div class="alert alert-secondary" role="alert">Affilation of the applicant or the applying organization (if applicable)</div></div><div class="tab-pane fade" role="tabpanel"
            id="checklist-catalytic-funding_application-components-narrative-questions-that-align-with-decisionmaking-criteria"
            aria-labelledby="checklist-catalytic-funding_application-components-narrative-questions-that-align-with-decisionmaking-criteria-list"
          ><div class="alert alert-secondary" role="alert">Questions you want your applicants to answer</div></div><div class="tab-pane fade" role="tabpanel"
            id="checklist-catalytic-funding_application-components-budget"
            aria-labelledby="checklist-catalytic-funding_application-components-budget-list"
          ><div class="alert alert-secondary" role="alert">Form or upload</div></div><div class="tab-pane fade" role="tabpanel"
            id="checklist-catalytic-funding_application-components-timeline"
            aria-labelledby="checklist-catalytic-funding_application-components-timeline-list"
          ><div class="alert alert-secondary" role="alert">Form or upload</div></div><div class="tab-pane fade" role="tabpanel"
            id="checklist-catalytic-funding_application-components-references-and-or-letters-of-support"
            aria-labelledby="checklist-catalytic-funding_application-components-references-and-or-letters-of-support-list"
          ><div class="alert alert-secondary" role="alert">Form or upload</div></div><div class="tab-pane fade" role="tabpanel"
            id="checklist-catalytic-funding_application-components-terms-and-conditions"
            aria-labelledby="checklist-catalytic-funding_application-components-terms-and-conditions-list"
          ><div class="alert alert-secondary" role="alert">Fine print and/or verification person has authorization to submit on behalf of org</div></div></div>
  </div>
</div>

Output:

* [x] **Applicant Contact Information**: Name, daytime phone, email address, social media for person completing the application who should receive follow-up
* [x] **Organizational Information**: Affiliation of the applicant or the applying organization (if applicable)
* [x] **Budget**: Form or upload

The script:

  1. Parses the id parameter from the include tag
  2. Loads the corresponding YAML file from _data/checklists/{id}.yml
  3. Renders each item as a markdown checkbox list item (* [x]) with bold item name
  4. Includes optional description after colon if present in YAML

Images

Input:

<div class="row justify-content-between align-items-center">
  <div class="col-12 col-xl-6 order-xl-last col-xxl-4">
    <img src="/downloads/community-building/what-is-community-building.gif" alt="What is community building?" class="img-fluid mt-3 mt-xl-0 mb-3 mb-xl-0" />

  </div>
  <div class="col-12 col-xl-6 order-xl-first col-xxl-8">
    <p>We think about our work as a campaign...</p>
  </div>
</div>

Output:

![What is community building?](/downloads/community-building/what-is-community-building.gif)

We think about our work as a campaign...

The script:

  1. Converts <img src="..." alt="…" class="" /> to markdown image syntax ![alt](src)
  2. Strips Bootstrap grid wrapper divs
  3. Preserves paragraph content alongside the image

Input:

* [Application Design](../../cultivating-applicants/application-design/)
* [Fundraising](../fundraising/)
* [External Link](https://example.com)

Output:

* [Application Design](https://fieldguide.sproutfund.org/catalytic-funding/cultivating-applicants/application-design/)
* [Fundraising](https://fieldguide.sproutfund.org/catalytic-funding/planning-preparing/fundraising/)
* [External Link](https://example.com)

The script converts all relative internal links to absolute URLs:

  1. Detects markdown links [text](path)
  2. Skips external links (starting with http:// or https://)
  3. Handles special anchor-only links using current page context:
    • #template-download--...https://fieldguide.sproutfund.org/resources/templates-downloads/#[page-slug]
    • #external-link--...https://fieldguide.sproutfund.org/resources/related-external-links/#[page-slug]
    • Where [page-slug] is the slug of the page being processed (e.g., “applicant-outreach-info-sessions”)
    • Other #anchors → kept as-is for in-page navigation
  4. Removes relative navigation (../) from paths
  5. Infers section based on:
    • Known directory structure (if path starts with a section name)
    • Known group names in the path (catalytic-funding or community-building groups)
    • Direct page slug mapping for common pages
  6. Constructs absolute URL with https://fieldguide.sproutfund.org

This ensures all links in the exported document point to the live Field Guide site, with anchor links directing to the appropriate section of the resources pages.

Other Cleanup

5. Increment Heading Levels

Uses regex with start-of-line anchor to shift heading levels:

def increment_headings(content, levels)
  content = content.gsub(/^###### /, '#' * (6 + levels) + ' ')
  content = content.gsub(/^##### /, '#' * (5 + levels) + ' ')
  content = content.gsub(/^#### /, '#' * (4 + levels) + ' ')
  content = content.gsub(/^### /, '#' * (3 + levels) + ' ')
  content = content.gsub(/^## /, '#' * (2 + levels) + ' ')
  content
end

Key feature: The ^ regex anchor ensures only headings at the start of lines are matched, preventing double-replacement issues that occur with simple string replacement.

6. Concatenate Output

Builds the final markdown file by concatenating:

7. Final Cleanup

Before writing the output file:

Configuration

Content Directories

The script searches these directories for markdown files:

CONTENT_DIRS = [
  'catalytic-funding',
  'community-building',
  'introduction',
  'lessons-learned',
  'resources',
  'about'
]

Add additional directories here if new top-level sections are added to the site.

Output File

OUTPUT_FILE = 'exports/FIELDGUIDE_all.md'

The exports/ directory is created automatically if it doesn’t exist. This directory is in .gitignore to avoid committing generated files.

Advantages Over Jekyll Template Approach

1. Proper Regex Support

Jekyll’s Liquid replace filter doesn’t support regex anchors, leading to issues like:


This replaces ALL occurrences of `## `, including:
- Actual headings: `## Overview` → `#### Overview` ✓
- Within URLs: `example.com/page## text` → `example.com/page#### text` ✗
- Mid-sentence: `text ## more` → `text #### more` ✗

Ruby's regex with `^` anchor solves this:

```ruby
content.gsub(/^## /, '#### ')  # Only matches at start of line

2. No Double-Replacement

Liquid’s sequential replacements can double-process:


If `######## ` contains `## `, it gets replaced again! Ruby processes each line once.

### 3. Speed

- **Jekyll build**: ~5-10 seconds (full site generation)
- **Ruby script**: <1 second (direct file processing)

### 4. Debugging

Ruby script provides console output showing progress:

Processing section: Catalytic Funding Processing group: Making Decisions Processing page: Application Intake Processing page: Committee Review


Warnings for missing files:

WARNING: Could not find file for ‘Page Title’


### Special Content Rendering

The script automatically detects special page types and renders their associated data inline.

#### Section-Level Content

For sections without sub-pages (like "Lessons Learned"), the script looks for an `index.md` file in the section directory and renders its content with subtitle support.

**Example:** `lessons-learned/index.md` → Renders full content under `# Lessons Learned`

### Experience/Technique Data Rendering

The script automatically detects experience and technique pages and renders their YAML data inline.

#### Experience Pages

**Detection:**
- Frontmatter has `layout: experiences`
- Frontmatter includes `experience: "Experience Name"`

**Rendering:**
```markdown
### Planning

**Target Size**: 5–10 people | **Attributes**: Small, Intentional, Focused | **Shorthand**: "I want to plan something."

#### Protips

* _As the saying goes..._ **Proper planning prevents poor performance.**
* **Don't start with a blank sheet of paper.**...

#### Process Checklist

* [x] Gather a planning team
* [x] Arrange a meeting (in-person, if possible)
...

**Related Experiences**: Fundraising, Kick-Off, Feedback...

**Related Techniques**: Affinity Clustering, Bullseye...

#### Example & Artifacts

Sprout designed and led a series of planning meetings...

The script:

  1. Parses frontmatter and detects layout: experiences
  2. Extracts the experience name from experience: field
  3. Loads matching experience from _data/community-building-experiences.yml
  4. Renders all fields: target size, attributes, shorthand, protips, process checklist, companions, related techniques, and examples

Technique Pages

Detection:

Rendering:

### Generate

#### Co-Creation Session

*Lead a hands-on working session and build something new together.*

A broad way to describe a hands-on, in-person session...

**Related Experiences**: Planning, Recruitment, Ideation...

#### Concept Posters

*Sketch out the details of a new idea.*

A great solo or group activity...

**Related Techniques**: Statement Starters, Concept Posters...

**Related Experiences**: Planning, Ideation...

The script:

  1. Parses frontmatter and detects layout: techniques
  2. Extracts category from page title (e.g., “Generate” from “Techniques to Generate”)
  3. Loads all techniques with that purpose from _data/community-building-techniques.yml
  4. Renders each technique with: name, tagline, description, related techniques, related experiences

Resources Pages

Templates & Downloads:

Related External Links:

Both resources pages provide complete aggregated lists of all templates and external links referenced throughout the Field Guide.

Future Enhancements

Filtered Exports

Add support for section-specific exports:

ruby export_fieldguide.rb --section catalytic-funding
# Output: exports/FIELDGUIDE_catalytic-funding.md

ruby export_fieldguide.rb --section community-building
# Output: exports/FIELDGUIDE_community-building.md

Custom Formatting

Add command-line options for output customization:

ruby export_fieldguide.rb --format=obsidian   # Obsidian-style links
ruby export_fieldguide.rb --format=notion     # Notion-specific formatting
ruby export_fieldguide.rb --format=llm        # Current default

Troubleshooting

Page Not Found

Issue: WARNING: Could not find file for 'Page Title'

Solutions:

  1. Check that the file exists in one of CONTENT_DIRS
  2. Verify filename matches slug convention: lowercase, hyphens, .md extension
  3. Check for index.md if page is in a subdirectory
  4. Add the parent directory to CONTENT_DIRS if needed

Incorrect Heading Levels

Issue: Content headings not at expected level

Debug:

  1. Check source markdown file - what heading levels are used?
  2. Verify page placement in nav.yml (grouped vs ungrouped)
  3. Confirm heading increment logic matches page hierarchy

Liquid Tags Not Removed

Issue: Liquid syntax appearing in export output

Solutions:

  1. Check if tag pattern is covered in cleanup_liquid_tags function
  2. Add new regex pattern for uncovered tag types
  3. Run with verbose output to see which files contain unhandled tags

Empty Content

Issue: Page title appears but no content

Debug:

  1. Check if frontmatter parsing is working (script skips content before 2nd ---)
  2. Verify file encoding (should be UTF-8)
  3. Check if page uses special layout that needs data file integration

Script Maintenance

When making changes to the export script:

  1. Test thoroughly - Run export and verify output in exports/FIELDGUIDE_all.md
  2. Check all page types - Ensure docs, experiences, techniques, voices all export correctly
  3. Validate hierarchy - Confirm heading levels create proper document structure
  4. Update this documentation - Document any new features or changes
  5. Consider edge cases - Test with special characters, long content, nested structures

Version History