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:
-
Proper regex support with
^anchor for start-of-line matching - Accurate heading level shifts without double-replacement issues
- Fast execution (no full Jekyll build required)
- Clean Liquid tag removal with precise control over formatting
File Location
Script: export_fieldguide.rb (in repository root)
Output: exports/FIELDGUIDE_all.md
Running the Export
VS Code
- Press
Cmd+Shift+P/Ctrl+Shift+P - Select “Tasks: Run Task”
- 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
-
Sections - Top-level navigation items (
# Introduction,# Catalytic Funding, etc.) -
Groups - Nested navigation groupings (
## Planning & Preparing,## Making Decisions, etc.) -
Pages - Individual content pages
-
###if within a group (e.g.,### Program Design) -
##if directly under section (e.g.,## Foreword)
-
-
Content headings - Shifted automatically:
- For grouped pages: Increment by 2 levels (
##→####) - For ungrouped pages: Increment by 1 level (
##→###)
- For grouped pages: Increment by 2 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:
- Converts title to slug (e.g., “Application Design” →
application-design) - Uses section and group context from navigation hierarchy for priority matching
- Search order:
-
Context-aware search (if section/group provided):
section-slug/group-slug/page-slug.mdsection-slug/group-slug/page-slug/index.mdsection-slug/**/page-slug.md
-
Global search in
CONTENT_DIRS(fallback):dir/slug.mddir/slug/index.mddir/**/slug.mddir/**/slug/index.md
-
Context-aware search (if section/group provided):
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:
- Parses the
idparameter from the include tag - Loads the corresponding YAML file from
_data/checklists/{id}.yml - Renders each item as a markdown checkbox list item (
* [x]) with bold item name - 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:

We think about our work as a campaign...
The script:
- Converts
<img src="..." alt="…" class="" />to markdown image syntax - Strips Bootstrap grid wrapper divs
- Preserves paragraph content alongside the image
Relative Link Conversion
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:
- Detects markdown links
[text](path) - Skips external links (starting with
http://orhttps://) - 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
-
- Removes relative navigation (
../) from paths - 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
- 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
- Removes `` references
- Removes
{:target="_blank"}Kramdown syntax - Replaces emoji shortcuts (
:heart:→ ❤️,:bulb:→ 💡,:warning:→ ⚠️)
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:
- Header with metadata (title, generation timestamp)
- Sections, groups, and pages in navigation order
- Content with adjusted heading levels
- Blank lines for proper markdown spacing
7. Final Cleanup
Before writing the output file:
- Joins all output array elements with newlines
- Collapses multiple consecutive blank lines (3+) to single blank lines
- Ensures clean, consistent spacing throughout the entire document
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:
- Parses frontmatter and detects
layout: experiences - Extracts the experience name from
experience:field - Loads matching experience from
_data/community-building-experiences.yml - Renders all fields: target size, attributes, shorthand, protips, process checklist, companions, related techniques, and examples
Technique Pages
Detection:
- Frontmatter has
layout: techniques - Page title used to determine technique category (generate/prioritize/reflect)
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:
- Parses frontmatter and detects
layout: techniques - Extracts category from page title (e.g., “Generate” from “Techniques to Generate”)
- Loads all techniques with that
purposefrom_data/community-building-techniques.yml - Renders each technique with: name, tagline, description, related techniques, related experiences
Resources Pages
Templates & Downloads:
- Detects
layout: templates-downloads - Loads all YAML files from
_data/templates-downloads/(catalytic-funding.yml, community-building.yml) - Renders hierarchically organized by section → page → items
- Format:
* **[Title](url)** [icon]with optional descriptions
Related External Links:
- Detects page title “Related External Links”
- Loads all YAML files from
_data/related-external-links/ - Renders hierarchically organized by section → page → items
- Format:
* **[Title](url)**with optional “via” attribution and descriptions
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:
- Check that the file exists in one of
CONTENT_DIRS - Verify filename matches slug convention: lowercase, hyphens,
.mdextension - Check for
index.mdif page is in a subdirectory - Add the parent directory to
CONTENT_DIRSif needed
Incorrect Heading Levels
Issue: Content headings not at expected level
Debug:
- Check source markdown file - what heading levels are used?
- Verify page placement in nav.yml (grouped vs ungrouped)
- Confirm heading increment logic matches page hierarchy
Liquid Tags Not Removed
Issue: Liquid syntax appearing in export output
Solutions:
- Check if tag pattern is covered in
cleanup_liquid_tagsfunction - Add new regex pattern for uncovered tag types
- Run with verbose output to see which files contain unhandled tags
Empty Content
Issue: Page title appears but no content
Debug:
- Check if frontmatter parsing is working (script skips content before 2nd
---) - Verify file encoding (should be UTF-8)
- Check if page uses special layout that needs data file integration
Related Documentation
- CONTENT_GUIDE.md: Guide to frontmatter and layouts
- DATA.md: Data file structures and usage
- CLAUDE.md: AI assistant guide for this repository
- README.md: Project overview and development setup
Script Maintenance
When making changes to the export script:
-
Test thoroughly - Run export and verify output in
exports/FIELDGUIDE_all.md - Check all page types - Ensure docs, experiences, techniques, voices all export correctly
- Validate hierarchy - Confirm heading levels create proper document structure
- Update this documentation - Document any new features or changes
- Consider edge cases - Test with special characters, long content, nested structures
Version History
-
v1.0 (2025-01-13): Initial Ruby script implementation with hierarchy support
- Basic navigation traversal
- Heading level incrementation
- Frontmatter stripping
-
v1.1 (2025-01-13): Enhanced file finding
- Added
index.mdsupport - Added
about/directory - Improved search patterns
- Added
-
v1.2 (2025-01-13): Liquid tag cleanup
- Thinking questions extraction
- Example blocks to blockquotes
- Baseurl removal
-
v1.3 (2025-01-13): Checklist support
- YAML checklist loading from
_data/checklists/ - Inline rendering as markdown checkboxes (
* [x]) with item names and descriptions - Support for both description and non-description formats
- YAML checklist loading from
-
v1.4 (2025-01-13): Image conversion
- Liquid image includes converted to markdown syntax
- Bootstrap grid wrapper cleanup
- Clean image/text layout in export
-
v1.5 (2025-01-13): Experience and technique data rendering
- Frontmatter parsing to detect special layouts
- Experience page data loaded from
_data/community-building-experiences.yml - Technique category data loaded from
_data/community-building-techniques.yml - Full rendering of protips, process checklists, related items, and examples
- Automatic cross-referencing between experiences and techniques
- Subtitle rendering from frontmatter for all pages
-
v1.6 (2025-01-13): Relative link conversion to absolute URLs
- All internal relative links converted to absolute URLs pointing to live site
- Section inference based on group names and directory structure
- Direct page slug mapping for common pages
- External links preserved unchanged
- Anchor links (#) preserved unchanged
-
v1.7 (2025-01-13): Context-aware file finding
- File lookup now uses section/group context from navigation hierarchy
- Prevents filename collisions (e.g., two
fundraising.mdfiles in different sections) - Priority search in context directory before falling back to global search
- Fixes issue where duplicate filenames would render the same content
-
v1.8 (2025-01-13): Content cleanup and polish
- Removes
{:target="_blank"}Kramdown syntax from links - Replaces emoji shortcuts with actual emojis (
:heart:→ ❤️,:bulb:→ 💡,:warning:→ ⚠️) - Collapses multiple consecutive blank lines to single blank lines
- Special anchor link handling for resources pages with page-slug context
- Section-level content rendering for sections without sub-pages (e.g., Lessons Learned)
- Resources pages YAML data rendering (Templates & Downloads, Related External Links)
- Removes
-
v1.9 (2025-01-13): Context-aware anchor link conversion
- Anchor links now use current page slug instead of original anchor
-
#template-download--...→resources/templates-downloads/#[page-slug] -
#external-link--...→resources/related-external-links/#[page-slug] - Enables proper navigation to relevant section on resources aggregation pages
- Moved blank line collapse to final cleanup step (before file write) for cleaner output