[Breaking] Dropped Ruby 3.2 support. Minimum required Ruby version is now 3.3.
[Fix] Heading Nesting in Normalize Mode — Fixed normalize_headings producing incorrect heading levels when same-level headings are nested under a parent.
Consecutive same-level headings (e.g., two ## headings) now correctly adjust the child's markdown level to be deeper than the parent's (e.g., ## → ###)
ATX closing hashes (## Title ##) are now stripped from titles before building hierarchical paths
[Fix] HTML-to-Markdown Section Nesting — Headings inside nested <section> elements now receive adjusted markdown levels based on section nesting depth.
<h2> inside a nested <section> under another <section> with its own <h2> is now correctly rendered as ### instead of ##
[Feature] Transform from URL — The transform command now accepts a remote URL via --url and processes fetched content through the standard transformer pipeline.
[Feature] llms.txt Specification Compliance - Updated output format to fully comply with the llms.txt specification from llmstxt.org.
Metadata Format: Metadata now appears within the description field using parentheses and comma separators: - [title](url): description (tokens:450, updated:2025-10-13, priority:high)
Optional Descriptions: Parser now correctly handles links without descriptions: - [title](url) per spec
Multi-Section Support: Documents automatically organized into Documentation, Examples, and Optional sections based on priority
Body Content Support: Added optional body config parameter for custom content between description and sections
Empty sections are automatically omitted from output
Updated parser regex from /^[-*]\s*\[([^\]]+)\]\(([^)]+)\):\s*(.*)$/m to /^[-*]\s*\[([^\]]+)\]\(([^)]+)\)(?::\s*([^\n]*))?$/ to make descriptions optional
Fixed multiline regex greedy matching issue that was capturing only one link per section
[Test] Added comprehensive test suite for spec compliance (8 new parser tests, 7 new generator tests)
[Docs] Updated README with multi-section organization examples and body content usage
Breaking Change: Metadata format has changed from tokens:450 updated:2025-10-13 to (tokens:450, updated:2025-10-13) for spec compliance
[Feature] Auto-Exclude Hidden Directories - Hidden directories (starting with .) are now automatically excluded by default to prevent noise from .git, .lint, .github, etc.
Adds include_hidden: false as default behavior
Set include_hidden: true in config to include hidden directories if needed
Uses Find.prune for efficient directory tree traversal
Prevents scanning of common directories like .lint, .gh, .git, node_modules (if hidden)
Fixed bug where root directory . was being pruned when used as docs_path
[Fix] Generate Command Excludes Support - The generate command now properly respects the excludes configuration option to filter out files from llms.txt generation.
Added should_exclude? method to Generator class that matches files against glob patterns
Supports both simple patterns (e.g., draft.md) and glob patterns (e.g., **/private/**, draft-*.md)
Uses File.fnmatch with FNM_PATHNAME and FNM_DOTMATCH flags for proper pattern matching
Checks patterns against both absolute and relative paths from docs_path
Excludes configuration works consistently with bulk-transform command
[Fix] Token Count from Transformed Content - Token counts in metadata now accurately reflect the actual content after applying transformations.
Token count is now calculated from transformed content when any transformation options are enabled
Adds has_transformations? helper method to detect if transformations are active
Ensures token metadata represents the actual size of processed content, not raw files
Falls back to raw content token count when no transformations are enabled
[Fix] Boolean Config Options - Fixed config merging bug where explicitly setting transformation options to false in YAML was being overridden to true.
Updated Config#merge_with_options to properly handle false values for boolean options
Fixed the || true pattern that was incorrectly treating false config values as falsy
Now correctly uses !self['option'].nil? check before falling back to defaults
Applies to all boolean transformation options: remove_comments, normalize_whitespace, remove_badges, remove_frontmatter
[Test] Added comprehensive unit tests for excludes functionality in Generator
[Test] Added integration tests for generate command with excludes and token counting