.--------------. .------------. .--------------. .-------------. .-----------. .--------------.
| __ | | _______ | | ______ | | ________ | | _____ | | ____ ____ |
| / \ | | / ___ | | | .' ___ | | | |_ __ | | | |_ _| | | |_ _||_ _| |
| / /\ \ | | | (__ \_| | | / .' \_| | | | |_ \_| | | | | | | \ \ / / |
| / ____ \ | | '.___`-. | | | | | | | _| | | | | | | > `' < |
| _/ / \ \_ | | |`\____) | | | \ `.___.'\ | | _| |_ | | _| |_ | | _/ /'`\ \_ |
||____| |____|| | |_______.' | | `._____.' | | |_____| | | |_____| | | |____||____| |
| | | | | | | | | | | |
'--------------' '------------' '--------------' '-------------' '-----------' '--------------'
║ ║ ║ ║ ║ ║
╚════════════════╩════════════════╩═══════════════╩═════════════════╩══════════════╝
Automatic ASCII diagram repair tool for Markdown files
Overview
ascfix fixes misaligned ASCII diagrams in Markdown, especially those generated by LLMs. It normalizes box widths, aligns arrows, enforces uniform padding, and ensures diagrams remain maintainable.
Ideal for:
- AI-generated documentation with ASCII diagrams
- Markdown files with workflow diagrams
- CI/CD pipeline documentation
- Architecture diagrams in code repositories
Quality Guarantees
ascfix prioritizes safety and reliability with a conservative approach:
Zero Data Loss
- Content preservation - designed to never delete or modify unintended text
- Non-destructive processing - safe to run on Markdown files
- Idempotent operations - running multiple times produces consistent results
- Conservative default - when uncertain, preserves original formatting
Intelligent Quality Assurance
- Automated quality validation - comprehensive test suite with 10+ passing unit fixtures
- Semantic transformation analysis - distinguishes beneficial improvements from potential corruption
- Context-aware processing - understands diagram elements vs. regular text
- Active development - complex nested structures handled conservatively
Professional Output
- Consistent formatting - uniform spacing, proper alignment for simple and moderate diagrams
- Basic nested box support - single-level nesting works reliably
- Arrow alignment - intelligent positioning for standard workflows
- Conservative mode - deeply nested (3+ levels) or complex overlapping structures preserved unchanged
Features
Processing Modes
- Safe mode (default): Normalize Markdown tables only - safest for any file
- Diagram mode: Repair ASCII boxes, arrows, and diagram structures
- Check mode: Validate without modifying (exit code 1 if changes needed - perfect for CI/CD)
- All mode: Shorthand for
--fences --mode=diagramto repair everything
Diagram Repair
- Box style preservation: Single-line (
┌┐└┘│─), double-line (╔╗╚╝║═), and rounded (╭╮╰╯│─) boxes - Box width normalization: Expands boxes to fit content with uniform padding
- Side-by-side balancing: Equalizes widths of adjacent boxes for visual consistency
- Nested box support: Parent boxes expand to properly contain children with margins
- Arrow alignment: Aligns vertical arrows to box centers, horizontal arrows to edges
- Connection lines: L-shaped paths with corner connectors
- Label preservation: Maintains text labels attached to primitives
Markdown Repair
- Table normalization: Aligns columns and fixes hard-wrapped cells
- List normalization: Standardizes bullet styles (
- * +→-), fixes indentation, adds spacing - Link preservation: Handles URLs with parentheses and reference-style links
- Fence repair: Fixes mismatched fence lengths, unclosed blocks, duplicate closing fences
File Operations
- Directory processing: Recursively process directories with automatic file discovery
- Multiple extensions: Process
.md,.mdx,.txtfiles (customizable with--ext) - Gitignore respect: Automatically respects
.gitignore(can be disabled with--no-gitignore) - Size limits: Configurable max file size (
--max-size 5MB) - In-place editing: Modify files directly with
--in-place(default: stdout output) - Error resilience: Continue processing remaining files on individual errors
Safety & Quality
- Conservative: Only fixes well-understood structures; unknown patterns preserved unchanged
- Idempotent: Running twice produces identical output (safe for repeated application)
- No panics: Handles malformed input gracefully without crashes
- Zero unsafe code: Compile-time enforced with
#![forbid(unsafe_code)] - No data loss: Never deletes or rewords content - only improves formatting
- Fast: Linear O(n) processing time suitable for large files and CI/CD
Integration
- Exit codes: 0 = success/no changes needed, 1 = check failed or error (CI/CD friendly)
- GitHub Actions ready: Verified workflows for testing, linting, security auditing
- Configuration file support:
.ascfix.tomlfor project-wide settings
Installation
From crates.io
From source
Usage
Single Files
# Check a file (default: safe mode, output to stdout)
# Fix a file in place (default: safe mode)
# Repair code fence boundaries
# Enable diagram mode for box/arrow repair
# Repair everything (fences + diagrams)
# Validate without modifying (check mode, exit code 1 if changes needed)
Directories
# Process all .md and .mdx files in a directory (respects .gitignore)
# Process a directory recursively
# Process only .md files (default includes both .md and .mdx)
# Process .mdx files only
# Process directories ignoring .gitignore
# Check multiple files without modifying
Modes
| Mode | Description | Use Case |
|---|---|---|
safe |
Fix only Markdown tables | Conservative, safe for any file |
diagram |
Fix boxes and arrows | For files with ASCII diagrams |
check |
Validate without writing | CI/CD validation |
Flags
| Flag | Short | Description | Default |
|---|---|---|---|
--in-place |
-i |
Modify files instead of printing to stdout | Off |
--check |
-c |
Validate files without modifying (returns exit code 1 if changes needed) | Off |
--fences |
Repair code fence boundaries | Off | |
--all |
Shorthand for --fences --mode=diagram |
Off | |
--mode |
Processing mode (safe, diagram, check) | safe | |
--ext |
-e |
File extensions to process (comma-separated, e.g., .md,.mdx) |
.md,.mdx |
--no-gitignore |
Do not respect .gitignore files | Off (respects .gitignore) | |
--max-size |
Maximum file size to process (e.g., "100MB", "1GB") | Unlimited |
Output & Formatting Flags
| Flag | Short | Description | Use Case |
|---|---|---|---|
--summary |
Print processing statistics (files processed, modified, errors) | Quick overview | |
--list-files |
Output only filenames that need fixing (one per line) | CI/CD, scripting | |
--verbose |
-v |
Show detailed processing information with colored output | Debugging, understanding |
--json |
Output results as JSON (machine-readable) | AI/programmatic use | |
--diff |
Show unified diff of changes without modifying files | Preview changes |
Ignore Markers
ascfix supports HTML comment markers to exclude specific content from processing. This is useful for:
- Preserving intentional ASCII art that shouldn't be "fixed"
- Protecting decorative elements like logos or banners
- Excluding complex diagrams that should remain unchanged
Supported marker syntax:
[content to ignore]
Or alternatively:
[content to ignore]
Example:
```
.----------------. .----------------.
This box will be processed:
┌──────┐
│ Test │
└──────┘
Content inside ignore markers is completely skipped by ascfix, regardless of mode. Ignore markers work with:
- Code fences (content inside fences within ignore blocks is preserved)
- Inline diagrams
- Tables
- Any other Markdown content
Important: Ignore markers are removed from the output (they're HTML comments, so they won't appear in rendered Markdown).
Examples
Safe Mode: Markdown Table Alignment
Before (inconsistent column widths):
After (normalized columns):
Command:
Code Fence Repair
Before (mismatched fence lengths):
```python
def hello():
`````
After (balanced fences):
`````python
def hello():
`````
Also handles:
- Unclosed fences (adds closing fence)
- Inconsistent lengths (uses longest)
- Preserves language specifiers
- Skips type mismatches (conservative approach)
Command:
Diagram Mode: Box and Arrow Alignment
Before (misaligned, inconsistent):
┌──────┐
│ Step │
└──────┘
┌─────────┐
│ Process │
└─────────┘
After (normalized):
┌────────┐
│ Step │
└────────┘
┌────────┐
│ Process│
└────────┘
Command:
Diagram Mode: Box Width Normalization
Before (text too close to border):
┌────────┐
│Process │
└────────┘
After (proper padding):
┌─────────┐
│ Process │
└─────────┘
Diagram Mode: Complex Workflow
Before (AI-generated, misaligned):
Source Code
┌──────────────────┐
│ Build & Test │
└──────────────────┘
↓
┌────────┐
│ Deploy │
└────────┘
After (normalized, consistent):
Source Code
┌─────────────────┐
│ Build & Test │
└─────────────────┘
┌──────────────────┐
│ Deploy │
└──────────────────┘
Diagram Mode: Box Padding and Arrow Alignment
Before (LLM-generated, text cramped against borders, arrows misaligned):
┌───────┐ ┌────────┐
│Process│ │Database│
└───────┘ └────────┘
↓ ↓
┌──────────────────┐
│ResultProcessor │
└──────────────────┘
After (proper padding added, arrows aligned to box centers):
┌─────────┐ ┌──────────┐
│ Process │ │ Database │
└─────────┘ └──────────┘
┌────────────────────────┐
│ Result Processor │
└────────────────────────┘
Changes made:
- Expanded boxes to fit content with 1-space padding
- Aligned arrows to box center columns
- Normalized interior spacing
Command:
Diagram Mode: Multi-Step Pipeline with Inconsistent Arrows
Before (arrows at inconsistent positions, no padding):
Source Code
↓
┌──────────┐
│Build │
└──────────┘
┌─────────────┐
│Test Suite │
└─────────────┘
↓
┌──────┐
│Deploy│
└──────┘
After (arrows normalized to consistent columns, boxes expanded with padding):
Source Code
┌──────────────┐
│ Build │
└──────────────┘
┌───────────────────┐
│ Test Suite │
└───────────────────┘
┌────────────┐
│ Deploy │
└────────────┘
Changes made:
- Aligned all vertical arrows to consistent column
- Added interior padding to all boxes (text no longer touching borders)
- Expanded boxes to fit content with proper spacing
Command:
Diagram Mode: Horizontal Workflow with Inconsistent Alignment
Before (arrows offset from box edges, inconsistent padding):
┌──────┐
│Input │
└──────┘
──→
After (arrows snapped to box edges, uniform padding):
┌────────┐
│ Input │
└────────┘
Changes made:
- Expanded boxes to fit content with padding
- Snapped arrow endpoints to box edge columns
- Made padding uniform (1 space) inside boxes
Command:
Check Mode: CI/CD Validation
Validate without modifying (useful for pull requests):
# Exit 0 if file is already normalized
# Exit 1 if file needs fixing
Perfect for GitHub Actions:
- name: Check diagram alignment
run: ascfix docs/*.md --check --mode=diagram
# Fails the build if any diagrams need fixing
Output Modes: Enhanced DX & AX
Summary mode - quick statistics:
Summary:
Total files processed: 15
Modified: 8
Unchanged: 7
Errors: 0
List files mode - for CI/CD scripts:
# Get list of files that need fixing
files=
if [; then
fi
JSON mode - for AI/programmatic use:
Diff mode - preview changes:
diff workflow.md
# Workflow
┌──────┐
-│Process│
+│ Process │
└──────┘
Verbose mode - debugging:
[verbose] Found 3 files to process
[success] Modified: docs/api.md
[verbose] Unchanged: docs/guide.md
[success] Modified: docs/workflow.md
Combined modes - maximum visibility:
Visual Examples Gallery
All examples below are verified test fixtures from our test suite (see tests/data/). Each example demonstrates specific features with real before/after transformations.
Box Style Variants
ascfix detects and preserves different box drawing styles:
Single-line boxes (┌ ┐ └ ┘ │ ─):
┌────────┐
│ Single │
└────────┘
Double-line boxes (╔ ╗ ╚ ╝ ║ ═):
╔════════════════╗
║ Double-Line ║
║ Box Style ║
╚════════════════╝
Rounded-corner boxes (╭ ╮ ╰ ╯):
╭────────────────╮
│ Rounded │
│ Corner Box │
╰────────────────╯
Side-by-Side Box Balancing
ascfix automatically normalizes widths of horizontally adjacent boxes:
Before:
┌───────┐ ┌─────┐ ┌────────────┐
│ Box 1 │ │ B2 │ │ Box Three │
└───────┘ └─────┘ └────────────┘
After:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Box 1 │ │ B2 │ │ Box Three │
└─────────────┘ └─────────────┘ └─────────────┘
Nested Box Hierarchies
Parent boxes expand to properly contain children with appropriate margins:
Before:
┌──────────────┐
│ Parent │
│ ┌────────┐ │
│ │ Child │ │
│ └────────┘ │
└──────────────┘
After:
┌────────────────────┐
│ Parent │
│ │
│ ┌──────────────┐ │
│ │ Child │ │
│ └──────────────┘ │
│ │
└────────────────────┘
CI/CD Pipeline Diagram
Real-world pipeline with consistent arrow alignment:
┌──────────────┐
│ Source Code │
└──────────────┘
↓
┌──────────────┐
│ Build Job │
└──────────────┘
↓
┌──────────────┐
│ Test Suite │
└──────────────┘
↓
┌──────────────┐
│ Deploy │
└──────────────┘
Complex Real-World Example
API documentation with mixed diagrams and tables:
┌─────────────────┐ ┌─────────────────┐
│ Client App │ │ API Gateway │
│ │ │ │
│ - Mobile App │ │ - Authentication │
│ - Web App │ │ - Rate Limiting │
└─────────┬───────┘ └─────────┬───────┘
│ │
▼ ▼
Test Suite & Fixtures
The project includes 55+ test fixtures organized in tests/data/:
Verified Working Examples:
- Safe mode fixtures: Table normalization, list formatting, link preservation
- Basic diagrams: Simple boxes, arrows, side-by-side alignment
- Standard workflows: CI/CD pipelines, simple nested structures
Edge Cases & Error Handling:
- Malformed inputs: Broken tables, wrapped cells
- Boundary conditions: Empty files, minimal diagrams
- Real-world patterns: API docs, ML pipelines (in conservative mode)
Conservative Mode Active: Some complex diagram fixtures (deep nesting, overlapping elements, mixed styles with labels) exercise the tool's conservative behavior. When structures are ambiguous or highly complex, ascfix preserves the original formatting unchanged rather than risk corruption. This prioritizes safety and data preservation over aggressive transformation.
Verify examples yourself:
# Run all tests to verify fixtures
# Process a specific file
tests/data/unit/- Simple, focused examplestests/data/integration/- Complex real-world scenariostests/data/integration/dirty/- Malformed inputs and error cases
Every example in this README can be verified:
# Run tests to verify all fixtures
# Process a specific fixture
Advanced Features in Diagram Mode
Box Style Variants
ascfix supports multiple box drawing styles and automatically preserves them:
Single-line boxes (default):
┌─────┐
│ Box │
└─────┘
Double-line boxes:
╔═════╗
║ Box ║
╚═════╝
Rounded-corner boxes:
╭─────╮
│ Box │
╰─────╯
All styles are detected, preserved, and normalized consistently. Mixed styles in the same diagram are handled correctly.
Nested Box Hierarchies
ascfix detects and supports basic parent-child box relationships. Single-level nesting works reliably:
Before (parent too small):
┌──────────────┐
│ Parent │
│ ┌────────┐ │
│ │ Child │ │
│ └────────┘ │
└──────────────┘
After (parent expanded with margins):
┌────────────────────┐
│ Parent │
│ │
│ ┌──────────────┐ │
│ │ Child │ │
│ └──────────────┘ │
│ │
└────────────────────┘
Important: Complex nested structures (>2 levels deep) or diagrams with overlapping elements are currently handled in conservative mode - they are preserved unchanged rather than risk corruption. This ensures safety over aggressive transformation.
Side-by-Side Box Alignment
ascfix automatically balances the width of horizontally adjacent boxes for visual consistency:
Before (inconsistent widths):
┌───────┐ ┌─────┐ ┌────────────┐
│ Box 1 │ │ B2 │ │ Box Three │
└───────┘ └─────┘ └────────────┘
After (uniform widths):
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Box 1 │ │ B2 │ │ Box Three │
└─────────────┘ └─────────────┘ └─────────────┘
Enhanced Arrow Support
ascfix recognizes and normalizes various arrow styles:
- Standard arrows:
→ ↓ ↑ ← - Double arrows:
⇒ ⇓ ⇑ ⇐ - Extended arrows:
⟶ ⟹
All arrows are aligned to box centers and maintained at consistent columns throughout the diagram.
Connection Lines (Conservative)
ascfix supports L-shaped connection paths with limited scope (4 segments maximum per connection):
┌────────┐
│ Start │
└───┬────┘
│
└─────┬─────────┐
│ │
┌───▼───┐ ┌──▼──┐
│ Path1 │ │Path2│
└───────┘ └─────┘
Connection detection is conservative to avoid false positives. Very complex paths are skipped.
Label Preservation (Framework)
ascfix includes framework support for preserving text labels attached to primitives during normalization. Label detection and rendering are currently conservative (skeleton implementation):
- Labels attached to boxes are tracked
- Labels attached to arrows are preserved
- Relative offsets are maintained during normalization
- Collision detection prevents label-diagram overlap
Building & Testing
# Run all tests
# Check code quality
# Build release binary
All code is tested with TDD discipline - unit tests, integration tests, and golden file tests. Test data is organized in tests/data/ with clear separation between unit and integration test cases.
Programmatic Usage
ascfix is designed for easy integration into scripts, AI agents, and CI/CD pipelines.
For AI Agents
Use JSON mode for structured output:
# Get machine-readable results
Parse the JSON to understand what changed:
For Shell Scripts
Use list-files mode for simple pipelines:
#!/bin/bash
# Fix all files that need it
for; do
done
Use exit codes for CI/CD:
# Exit 0 if all files are clean, 1 if fixes needed
if [; then
fi
For Python Scripts
=
=
=
GitHub Actions Integration
name: Validate Diagrams
on:
jobs:
check-diagrams:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install ascfix
run: cargo install ascfix
- name: Check diagrams
run: |
ascfix docs/ --check --summary --mode=diagram
if [ $? -ne 0 ]; then
echo "::error::Diagrams need normalization. Run: ascfix docs/ --in-place --mode=diagram"
exit 1
fi
Documentation
User Guides
- CONFIG.md - Configuration options, file formats, and examples
- LIBRARY_USAGE.md - Using ascfix as a Rust library, API documentation, and integration examples
Reference
- ARCHITECTURE.md - Design overview, module structure, and data flow
- SECURITY.md - Security policies, audit status, and best practices
- CONTRIBUTING.md - Development guidelines and contribution process
- CHANGELOG.md - Version history and release notes
- tests/README.md - Test data organization and testing approach
License
Licensed under the MIT License (LICENSE or https://opensource.org/licenses/MIT)
Contribution
Contributions are welcome! Please feel free to submit pull requests.