FrontRange CLI Expert
Comprehensive guidance for using the FrontRange CLI (fr) to manage YAML front matter in text documents.
Core Concepts
What is Front Matter?
Front matter is YAML metadata at the beginning of a text file, enclosed by --- delimiters:
--- title: My Blog Post draft: true tags: ["swift", "tutorial"] date: 2025-01-15 --- # Blog Post Content This is the body of the document...
How to Invoke the CLI
Recommended (installed globally):
fr <command>
During development (from FrontRange project directory):
swift run fr <command>
DO NOT USE swift run fr unless developing or testing FrontRange itself.
Quick Start: Essential Commands
Read a Value
# Single file fr get --key title post.md # All files in directory recursively fr get --key title posts/ -r
Write a Value
# Single file fr set --key draft --value false post.md # All files recursively fr set --key published --value true posts/ -r
Search for Files
# Find all drafts (ALWAYS recursive) fr search 'draft == `true`' ./posts # Complex query fr search 'draft == `false` && contains(tags, `"swift"`)' ./posts
Bulk Operations (Piping)
# Update all matching files fr search 'draft == `true`' ./posts | while read -r file; do fr set "$file" --key draft --value false fr set "$file" --key publishDate --value "$(date +%Y-%m-%d)" done
Critical Non-Obvious Behaviors
1. Search is ALWAYS Recursive
Unlike other commands, search always searches recursively - no -r flag needed:
# Other commands: explicit recursive flag required fr get --key title posts/ # Only direct children fr get --key title posts/ -r # Includes subdirectories ✓ # Search: ALWAYS recursive automatically fr search 'draft == `true`' posts/ # Searches ALL subdirectories ✓
2. JMESPath Literal Syntax - THE ONE TRUE WAY
ALWAYS use this exact syntax for search queries:
- •Wrap entire expression in SINGLE QUOTES
- •Use BACKTICKS around ALL literals
# CORRECT ✓ fr search 'draft == `true`' . fr search 'status == `"published"`' . fr search 'count > `100`' . fr search 'contains(tags, `"swift"`)' . # WRONG ✗ fr search draft == `true` . # Missing quotes fr search "draft == `true`" . # Wrong quotes (shell interprets backticks) fr search 'draft == true' . # Missing backticks around literal
Common JMESPath patterns:
# Equality 'draft == `true`' 'status == `"published"`' # Arrays 'contains(tags, `"tutorial"`)' # Boolean logic 'draft == `false` && featured == `true`' 'status == `"draft"` || status == `"review"`' # Comparisons 'views > `1000`' 'rating >= `4.5`'
3. Directory Processing Modes
Default: Most commands only process files in the specified directory (non-recursive).
Recursive: Use --recursive / -r flag to include subdirectories.
Exception: search is ALWAYS recursive.
# Process only posts/ directory (direct children) fr get --key title posts/ # Process posts/ and all subdirectories fr get --key title posts/ --recursive # Short form fr get --key title posts/ -r
4. Extension Filtering
Default extensions: md, markdown, yml, yaml
Override with --extensions / -e:
# Only markdown files fr get --key title docs/ -r --extensions md # Multiple extensions fr list content/ --extensions txt,md,rst # All files (empty string) fr search 'title' . --extensions ""
Common Commands Overview
For complete command reference, see references/commands.md.
| Command | Purpose | Example |
|---|---|---|
get | Retrieve value | fr get --key title post.md |
set | Set/update value | fr set --key draft --value false post.md |
has | Check key exists | fr has --key author post.md |
list | List all keys | fr list post.md |
remove | Delete key | fr remove --key temp post.md |
rename | Rename key | fr rename --old-key tag --new-key tags post.md |
sort-keys | Alphabetize keys | fr sort-keys post.md |
lines | Show line numbers | fr lines post.md |
dump | Export front matter | fr dump post.md --format json |
search | Query files (JMESPath) | fr search 'draft == \true`' ./posts` |
replace | Replace entire front matter | fr replace post.md --data '{}' --format json |
Bulk Operations
The search command outputs file paths (one per line), enabling powerful piping:
Using while loops (Recommended)
Handles spaces, special characters, and large file sets:
# Publish and date-stamp matching posts fr search 'draft == `true`' ./posts | while read -r file; do fr set "$file" --key published --value true fr set "$file" --key date --value "$(date +%Y-%m-%d)" done
Using xargs (Simple cases only)
Works for small file sets without spaces in paths:
# Simple bulk update
fr search 'draft == `true`' ./posts | xargs fr set --key draft --value false
# With spaces: use -I flag
fr search 'tags' . | xargs -I {} fr get --key tags "{}"
When to use each:
- •
while read: Paths with spaces, 100+ files, multi-step operations - •
xargs: <100 files, no spaces, simple one-liners
For detailed piping patterns, see references/examples.md.
Output Formats
Most commands support --format / -f for output formatting:
# YAML (default for most commands) fr get --key tags post.md --format yaml # JSON fr get --key tags post.md --format json # Plain string (no formatting) fr get --key title post.md --format plainString # Dump supports additional formats fr dump post.md --format plist # Apple PropertyList XML fr dump post.md --format yaml --include-delimiters
Handling Missing Keys
Not all files have all keys. Commands error when keys are missing:
$ fr get --key tags post.md Error: Key 'tags' not found in frontmatter.
Strategies:
- •
Filter with search first:
bashfr search 'tags' . | while read -r file; do fr get --key tags "$file" done
- •
Suppress expected errors:
bashfr get --key tags posts/ -r 2>/dev/null
- •
Check for errors in scripts:
bashif fr has --key tags "$file" 2>/dev/null; then fr get --key tags "$file" fi
Common Workflows
Publishing Workflow
# Find drafts ready to publish fr search 'draft == `true` && ready == `true`' ./posts # Publish them fr search 'draft == `true` && ready == `true`' ./posts | while read -r file; do fr set "$file" --key draft --value false fr set "$file" --key published --value true fr set "$file" --key publishDate --value "$(date +%Y-%m-%d)" done
Content Auditing
# Get all authors fr get --key author content/ -r --format json # Count by status fr search 'status == `"draft"`' posts | wc -l fr search 'status == `"published"`' posts | wc -l # List unique tags fr get --key tags posts/ -r --format json | jq -r '.[]' | sort -u
Batch Updates
# Add key to all files fr set --key version --value "2.0" content/ -r # Rename keys across project fr rename --old-key category --new-key categories . -r # Remove deprecated keys fr search 'oldField' . | xargs fr remove --key oldField
For more patterns and recipes, see references/examples.md.
Global Options
Available across most commands:
- •Path arguments: File(s) and/or directory(ies) to process
- •
--recursive/-r: Process subdirectories (default: false, exceptsearchwhich is always recursive) - •
--extensions/-e: File extensions to process (default:md,markdown,yml,yaml) - •
--format/-f: Output format (yaml,json,plainString) - •
--debug/-d: Enable debug output
Quick Reference: When to Use Each Approach
Single File Operations
fr get --key title post.md fr set --key draft --value false post.md
Directory Operations (Non-Recursive)
fr get --key title posts/ # Only direct children fr set --key reviewed --value true posts/
Directory Operations (Recursive)
fr get --key title posts/ -r # All subdirectories fr set --key category --value "blog" content/ -r
Query-Based Operations
# Search (always recursive) + pipe to other commands fr search 'draft == `true`' . | xargs fr set --key draft --value false # With while loop for safety fr search 'ready == `true`' . | while read -r file; do fr set "$file" --key published --value true done
Additional Documentation
- •references/commands.md - Complete command reference with all options and flags
- •references/examples.md - Detailed patterns, recipes, and workflows
- •references/troubleshooting.md - Troubleshooting guide and advanced usage
Summary
Key Principles:
- •Search is always recursive - no
-rflag needed - •JMESPath requires backticks -
'draft == \true`'not'draft == true'` - •Most commands need
-rfor subdirectories - except search - •Pipe search results for bulk operations -
fr search ... | xargs fr set ...
The FrontRange CLI provides a complete toolkit for managing YAML front matter with powerful directory processing, flexible querying, and seamless bulk operations.