AGENTS.md - markly-merge Development Guide
π― Project Overview
markly-merge is a format-specific implementation of the *-merge gem family for Markdown files using the Markly parser. It provides intelligent Markdown file merging using AST analysis.
Core Philosophy: Intelligent Markdown merging that preserves structure, formatting, and links while applying updates from templates.
Repository: https://github.com/kettle-rb/markly-merge
Current Version: 1.0.0
Required Ruby: >= 3.2.0 (currently developed against Ruby 4.0.1)
ποΈ Architecture: Format-Specific Implementation
What markly-merge Provides
-
Markly::Merge::SmartMergerβ Markdown-specific SmartMerger implementation -
Markly::Merge::FileAnalysisβ Markdown file analysis with section extraction -
Markly::Merge::NodeWrapperβ Wrapper for Markly AST nodes -
Markly::Merge::PartialTemplateMergerβ Section-level partial merges -
Markly::Merge::MergeResultβ Markdown-specific merge result -
Markly::Merge::ConflictResolverβ Markdown conflict resolution -
Markly::Merge::FreezeNodeβ Markdown freeze block support -
Markly::Merge::DebugLoggerβ Markly-specific debug logging
Key Dependencies
| Gem | Role |
|---|---|
ast-merge (~> 4.0) |
Base classes and shared infrastructure |
tree_haver (~> 5.0) |
Unified parser adapter (wraps Markly) |
markly (~> 0.15) |
CommonMark Markdown parser (MRI only) |
version_gem (~> 1.1) |
Version management |
Parser Backend
markly-merge uses the Markly parser exclusively via TreeHaverβs :markly backend:
| Backend | Parser | Platform | Notes |
|---|---|---|---|
:markly |
Markly | MRI only | Fast CommonMark parser, native extension |
π Project Structure
lib/markly/merge/
βββ smart_merger.rb # Main SmartMerger implementation
βββ partial_template_merger.rb # Section-level merging
βββ file_analysis.rb # Markdown file analysis
βββ node_wrapper.rb # AST node wrapper
βββ merge_result.rb # Merge result object
βββ conflict_resolver.rb # Conflict resolution
βββ freeze_node.rb # Freeze block support
βββ debug_logger.rb # Debug logging
βββ version.rb
spec/markly/merge/
βββ smart_merger_spec.rb
βββ partial_template_merger_spec.rb
βββ file_analysis_spec.rb
βββ integration/
π§ Development Workflows
Running Tests
# Full suite
bundle exec rspec
# Single file (disable coverage threshold check)
K_SOUP_COV_MIN_HARD=false bundle exec rspec spec/markly/merge/smart_merger_spec.rb
# Markly backend tests
bundle exec rspec --tag markly
Coverage Reports
cd /home/pboling/src/kettle-rb/ast-merge/vendor/markly-merge
bin/rake coverage && bin/kettle-soup-cover -d
π Project Conventions
API Conventions
SmartMerger API
-
mergeβ Returns a String (the merged Markdown content) -
merge_resultβ Returns a MergeResult object -
to_son MergeResult returns the merged content as a string
PartialTemplateMerger API
-
mergeβ Merges a template section into a specific location in destination - Used by
ast-merge-recipefor section-level updates
Markdown-Specific Features
Heading-Based Sections:
# Section 1
Content for section 1
## Subsection 1.1
Nested content
# Section 2
Content for section 2
Freeze Blocks:
<!-- markly-merge:freeze -->
Custom content that should not be overridden
<!-- markly-merge:unfreeze -->
Standard content that merges normally
Link Reference Preservation:
[link text][ref]
[ref]: https://example.com
π§ͺ Testing Patterns
TreeHaver Dependency Tags
Available tags:
-
:marklyβ Requires Markly backend -
:markdown_parsingβ Requires Markdown parser
β CORRECT:
RSpec.describe Markly::Merge::SmartMerger, :markly do
# Skipped if Markly not available
end
β WRONG:
before do
skip "Requires Markly" unless defined?(Markly) # DO NOT DO THIS
end
π‘ Key Insights
- Heading-based structure: Sections matched by heading text
-
.textstrips formatting: When matching by text, backticks and other formatting are removed - Link references preserved: Reference-style links maintained during merge
- PartialTemplateMerger: Supports injecting template sections into specific locations
-
Freeze blocks use HTML comments:
<!-- markly-merge:freeze --> - MRI only: Markly requires native extensions, MRI only
π« Common Pitfalls
- Markly requires MRI: Does not work on JRuby or TruffleRuby
-
NEVER use manual skip checks β Use dependency tags (
:markly) - Text matching strips formatting β Match on plain text, not markdown syntax
- Do NOT load vendor gems β They are not part of this project; they do not exist in CI
-
Use
tmp/for temporary files β Never use/tmpor other system directories
π§ Markdown-Specific Notes
Node Types
document # Root node
heading # # Heading
paragraph # Regular text
code_block # ```code```
list # - item or 1. item
link # [text](url)
image # 
Text Matching Behavior
Source: ### The `*-merge` Gem Family
.text: "The *-merge Gem Family\n"
# Backticks, bold, italic stripped in .text
Merge Behavior
- Headings: Matched by heading text (stripped of formatting)
- Sections: Content from heading to next same-level heading
- Paragraphs: Position-based within sections
- Code blocks: Matched by language and content
- Lists: Can be merged or replaced
- Links: Reference-style links preserved
- Freeze blocks: Protect customizations from template updates