Development

May 28, 2026 · View on GitHub

Doc status: Parallel to upstream docs/development.md. Both cover the same role; content differs because the Rust toolchain (cargo, multi-channel release) and the Python toolchain (uv, PyPI-only) require different commands and steps.

How to build, test, and work on flowmark-rs.

Prerequisites

  • Rust 1.85+ (see rust-version in Cargo.toml for MSRV)
  • Python flowmark v0.7.0: for cross-binary parity tests (uv tool install flowmark==0.7.0)
  • Node.js 22+ and tryscript: for golden CLI tests (npm install -g tryscript@latest)

All test dependencies are required. Tests fail loudly when a dependency is missing, there is no skip logic.

Building

cargo build --all-features

The --all-features flag enables the cli feature gate, which includes the binary entry point and clap/anyhow dependencies. Without it, only the library crate is built.

Testing

cargo test --all-features

The full suite (501 tests) includes:

CategoryDescription
Unit tests (src/)Module-level tests for parsers, formatters, wrappers
Integration tests (tests/)Full-pipeline formatting, CLI, file discovery
Doc testsLibrary API usage example
Tryscript golden testsEnd-to-end CLI behavior specs
D11 parity testsCross-binary comparison (invokes both Python and Rust)

Zero #[ignore] annotations. Zero skipped tests.

Linting

cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings

The project uses pedantic clippy lints at deny level. unsafe_code and unwrap_used are denied in Cargo.toml.

Project Structure

Input → [YAML Frontmatter] → [comrak Parse] → [Typography] → [Cleanups] → [fill_markdown] → Output
ModulePython SourcePurpose
formatter/filling.rsflowmark/filling.pyCore Markdown rendering pipeline
formatter/markdown.rsflowmark/formats/flowmark_markdown.pycomrak configuration and workarounds
parser/frontmatter.rsflowmark/frontmatter.pyYAML frontmatter preservation
wrapping/text_filling.rsflowmark/text_filling.pyPlaintext wrapping
wrapping/text_wrapping.rsflowmark/text_wrapping.pyMarkdown-aware word splitting
wrapping/sentence.rsflowmark/sentence.pySentence boundary detection
wrapping/line_wrappers.rsflowmark/line_wrappers.pyLine wrapper composition
transform/cleanups.rsflowmark/cleanups.pySafe document cleanups
typography/quotes.rsflowmark/smartquotes.pySmart quote conversion
typography/ellipses.rsflowmark/ellipses.pyEllipsis conversion
file_resolver/flowmark/file_resolver.pyFile discovery and filtering
config.rsflowmark/config.pyTOML config loading, three-way merge
lib.rsflowmark/__init__.pyPublic API
main.rsflowmark/__main__.pyCLI entry point

Key design decisions:

  • Feature-gated CLI: library usable without clap/anyhow via --no-default-features
  • Zero unsafe code: unsafe_code = "deny" (1 exception: SIGPIPE handler in main.rs)
  • No unwrap() in library: unwrap_used = "deny"; all errors use ? or expect() with messages
  • Pedantic clippy at deny level: catches issues locally, not just in CI
  • Atomic file writes: tempfile + persist pattern prevents corruption
  • 13 comrak workarounds: each tagged COMRAK-WORKAROUNDn in src/formatter/filling.rs

CI Pipeline

The CI runs 12 checks on every push and PR:

JobWhat It Checks
fmtcargo fmt --check
clippyPedantic clippy with -D warnings
test (Ubuntu + macOS)Full test suite with Python parity + tryscript golden tests
test-lib-onlyLibrary builds and tests without CLI feature
msrvCompiles on minimum supported Rust version (1.85)
denyLicense allowlist and supply chain audit
docscargo doc with -D warnings
coveragecargo-llvm-cov with Codecov upload
semver-checksAPI breakage detection (PRs only)
markdown-fmtMarkdown formatting consistency
check-mappingTest mapping completeness (347 Python tests: 323 mapped + 24 excluded)
readme-syncREADME generation stays in sync with template

Configuration

Flowmark supports TOML-based configuration. It searches for config files in this order (first match wins, walking up directories):

  1. .flowmark.toml
  2. flowmark.toml
  3. pyproject.toml (only if it has a [tool.flowmark] section)

A .flowmarkignore file (gitignore syntax) can exclude paths from formatting.

Rust-Only Features

The Rust port adds performance features not present in Python:

  • Incremental cache (--no-cache, --cache-dir, --show-cache, --clear-cache)
  • Parallel file processing (--threads)
  • Stage-level performance stats (--perf-stats)

See docs/rust-only-features.md and docs/cache.md for details.

Releasing

See docs/publishing.md for the full release runbook (crates.io, PyPI, GitHub Releases, Homebrew tap).

Port Sync

For syncing with new Python flowmark upstream releases, see docs/port-sync-playbook.md.

For the full port overview and parity verification history, see docs/port-status.md.