# Flowmark-rs
**Port of [Flowmark](https://github.com/jlevy/flowmark) to Rust**
Flowmark-rs is a high-performance AI-generated Rust mirror port of the Flowmark
Python-based auto-formatter.
Flowmark is among the most complete and flexible auto-formatters for Markdown, with
optional **line wrapping**, **semantic line breaks**, **typographic transformations**,
and full support for **GitHub-flavored Markdown**. See the [original
package]((<https://github.com/jlevy/flowmark>) for more.
## About the Port
This Rust implementation is mirror port with feature parity with the Python Flowmark
library.
Output is byte-for-byte identical except a few remaining corner cases due to parser
libraries (comrak vs marko): see
[cross-validation-assessment.md](docs/project/cross-validation-assessment.md) for
detailed remaining issues.
### Why?
I made this complete port using Claude Code in about a day.
I’m completely new to Rust but experienced at Python and agent coding so wanted to see
how fully this process could be automated for a relatively complex but still
self-contained CLI like Flowmark.
Every line of Rust was written by Claude.
A significant amount of the architecture and testing process was organized by me up
front and a few of the trickier parts required guidance from me during the bug-fixing
phase.
Much of the process was surprisingly smooth it should not be hard to have it continue to
mirror features and fixes to the Python version.
Because I wanted the result to be correct and usable as a replacement for the Python
implementation, I took time to research and document best practices for Rust port.
Comprehensive documentation from the porting process is in the `docs/` directory.
### The Overall Porting Process
I’ve written notes on the entire process for Claude-based port, and you can also see the
Git commits and merged PRs in the repo here.
1. **Background Research:** (About an hour.)
First, I instructed Claude to do background research on best practices for Rust CLIs
and carefully reviewed these, to get the **[Rust CLI Best
Practices](docs/rust-cli-best-practices.md)** doc.
2. **Porting Plan:** (About an hour.)
Then, I worked with Claude in a separate session to create a **[Python to Rust
Migration Plan](docs/project/flowmark-rust-migration-plan.md)**. The key thing was to
map out libraries and tools and how to ensure *exact* feature parity, using the fairly
complete tests that are in the Python implementation.
A key part was encouraging it to look at all libraries and evaluate which are best
given the Python system’s use of a highly customized Marko parser.
3. **Additional Plans:** (About an hour, in parallel with the previous step.)
I also chatted with Claude to get a **[CI/CD and Publishing
Plan](docs/project/ci-cd-publishing-plan.md)**, again insisting it carefully research
for best modern practices.
The key thing was to insist that Claude *exactly* reproduce all tests, as well as
write additional tests as it goes.
I iterated a little get a generic **[Port Checklist
Template](docs/general/port-checklist-initial-template.md)** to ensure we covered all
the necessary steps and used it as a
[port checklist](docs/project/port-checklist-initial-2025-11-02.md).
As a sanity check, I also used GPT-5 High to review these docs and accepted a few more
minor suggestions for improvements.
4. **Initial Implementation:** (2-3 hours.)
This was nearly the longest part.
I had Claude work through the plan piece by piece, each time reminding it to follow
*exactly* all the tests in Python, optionally adding more for test-driven development
as it progressed. It required encouragement to continue 8 or 9 times, as there was a
lot to implement, but it was basically the same prompt every time, and a couple cases
where I insisted it must fix 100% of tests before going to the next phase.
5. **Bug-fixing:** (2-3 hours.)
This was the most painful part.
I did all this in Claude Code cloud, so I could use multiple work trees and not be
waiting on the slow parts.
For this reason, I had
[several PRs](https://github.com/jlevy/flowmark-rs/pulls?q=is%3Apr+is%3Aclosed) for
these steps, and merged them as I went.
But at this point I switched to local Claude Code, so I could have it use `gh` to
manage and monitor PRs.
Many corner cases arose that were only partly covered in the tests, or where Claude
got confused by intricacies of line wrapping and Markdown specifics that were
different in the Python and Rust libraries.
It would keep insisting the results were close enough but I allowed zero tolerance.
This led to finding about a dozen other corner case issues.
A couple were actual bugs in the Python implementation, so I used them to produce a
new test doc and extend the tests in Python version and fix them (again with Claude
Code). Then update the submodule to use the new Python release.
Claude took a lot longer here.
I had to remind it several times to go read the code carefully and understand a
problem, rather than try to work around it.
I also had to make it read the code to comrak to identify specific flags and logic.
This identified at least one bug in comrak and about a dozen other differences between
comrak and Python’s marko library.
I had it implement workarounds for bugs we could not fix.
**See [cross-validation-assessment.md](docs/project/cross-validation-assessment.md)**
for comprehensive documentation of all comrak vs marko parser differences found during
porting. After a bunch of iteration, Claude finally got most of the key issues
corrected. Most are now fixed but a few are remaining as we need to vendor the
dependencies to fix them all.
(I’ll revisit these again soon, after another small bugfix or two to the original
Python version related to obscure escaping conventions.)
## Installation
### Pre-built Binaries (Recommended)
Download pre-built binaries from the
[Releases page](https://github.com/jlevy/flowmark-rs/releases)
**Binary name:** `flowmark` (matching the Python version).
**Supported platforms:** Linux x86\_64 (glibc and musl/static), Linux ARM64, macOS Intel
(x86\_64), macOS Apple Silicon (ARM64), Windows x86\_64
### From Source
```bash
git clone --recursive https://github.com/jlevy/flowmark-rs.git
cd flowmark-rs
cargo build --release
```
Binary will be available at:
- `target/release/flowmark`
### Using Cargo (When Published)
```bash
# Coming soon to crates.io
cargo install flowmark
```
## Usage
```bash
# Format a file, print to stdout
flowmark document.md
# Format with semantic line breaks
flowmark --semantic document.md
# Auto mode (all features, editing in place)
flowmark --auto document.md
# Custom line width
flowmark --width 100 document.md
# From stdin
### Command-Line Options
```
flowmark [OPTIONS] [FILE]
Options:
-w, --width <WIDTH> Line width to wrap to, or 0 to disable [default: 88]
-p, --plaintext Process as plaintext (no Markdown parsing)
-s, --semantic Enable semantic (sentence-based) line breaks
-c, --cleanups Enable cleanups for common issues
--smartquotes Convert straight quotes to typographic quotes
--ellipses Convert ... to … character
-i, --inplace Edit the file in place
--nobackup Do not make a backup when using --inplace
--auto Full auto-formatting (all features)
-j, --json Output in JSON format (line-delimited)
-v, --verbose Increase logging verbosity (-v, -vv, -vvv)
-h, --help Print help
-V, --version Print version
```
## Architecture
Flowmark is a single Rust package with both library and binary components:
```
flowmark-rs/
├── src/ # Source code (library + binary)
├── tests/ # Integration tests
├── .github/workflows/ # CI/CD pipelines
└── docs/ # Documentation
```
**Modern tooling:**
- CLI framework: [clap](https://docs.rs/clap) v4 (derive API)
- Error handling: [color-eyre](https://docs.rs/color-eyre)
- Logging: [tracing](https://docs.rs/tracing)
- Markdown parser: [comrak](https://docs.rs/comrak) (GitHub Flavored Markdown)
## Development and Testing
See [development.md](development.md) for complete development workflows, testing
procedures, release process, and CI/CD documentation.