Skip to main content

img

Table of Contents

About

A fast, format-aware semantic line break formatter. Reformats prose so each sentence occupies its own line, producing minimal and meaningful git diffs when collaborating on documents.

Why?

When multiple authors collaborate on a paper using Git, traditional line wrapping at a fixed column width causes problems. A single word change can trigger a diff that spans an entire paragraph. By breaking at sentence boundaries instead, each edit affects only the sentence that changed.

This convention, often called semantic line breaks, enjoys longstanding support from technical writers. snapper is a deterministic formatter (UAX #29 plus abbreviation tables and optional nnsplit). It is not admk/sembr (learned clause breaks) and not sembr/skills (agent rewrite instructions). latexindent.pl covers LaTeX only; snapper is a standalone Rust binary for Org-mode, LaTeX, Markdown, RST, and plaintext.

Design

snapper runs a three-stage pipeline:

  • Parse: Classify input into prose regions and structure regions
  • Split: Detect sentence boundaries in prose regions
  • Emit: Output each sentence on its own line

Math environments, tables, front matter, drawers, and non-source comments pass through unchanged. Fenced and delimited source blocks are Region::Code: fence/open/close lines stay structure, non-comment code stays verbatim, and comment lines reflow at sentence boundaries when the language has a [code.<lang>] entry in .snapperrc.toml (snapper init seeds common languages). Pass --format-code to also pipe each block body through an optional per-language formatter argv (missing binary, non-zero exit, and timeouts degrade to the reflowed body). Sentence detection relies on Unicode UAX #29 segmentation with abbreviation-aware post-processing that avoids false breaks at titles (Dr., Prof.), references (Fig., Eq.), journal titles (J. Chem. Phys., SIAM J. Sci. Comput.), and Latin terms (e.g., i.e., et al.). Org emphasis (*bold*, /italic/, _underline_, +strike+) is kept atomic so splits cannot open a pseudo-headline mid-span. Markdown *em* / **strong** (CommonMark flanking) and GFM ~~strike~~ are kept atomic the same way.

Installation

Pre-built binary (fastest):

cargo binstall snapper-fmt

cargo binstall fetches the archive for your platform from the GitHub release and never compiles. Each release ships archives for Linux on x86_64 and aarch64 (glibc, and static musl for Alpine and minimal containers), macOS on x86_64 and Apple silicon, and Windows on x86_64 (a zip). The static musl builds cannot load the optional in-process pandoc library, so --use-pandoc there runs the pandoc on PATH.

Shell one-liner (Linux/macOS):

curl -LsSf https://github.com/TurtleTech-ehf/snapper/releases/latest/download/snapper-fmt-installer.sh | sh

Homebrew:

brew install TurtleTech-ehf/tap/snapper-fmt

pip:

pip install snapper-fmt

conda-forge:

conda install -c conda-forge snapper-fmt

Compile from source:

cargo install snapper-fmt

Nix:

nix build github:TurtleTech-ehf/snapper

The crate is snapper-fmt on all registries. Each install ships two CLI names for the same program: snapper and snapper-fmt.

Name collision: openSUSE snapper is a different project (Btrfs/LVM snapshots) that also installs a snapper binary. On systems where that tool already owns /usr/bin/snapper, call this formatter as snapper-fmt, or put the TurtleTech install path ahead of the system path.

Usage

Format a file (output to stdout):

snapper paper.org

Format in place:

snapper --in-place paper.org

Pipe through stdin (for editor integration):

cat draft.org | snapper --native --format org

The CLI uses the native line parsers unless --use-pandoc is set or .snapperrc.toml sets use_pandoc = true. --native is accepted and selects those same parsers. --use-pandoc requires pandoc (error if missing). Markdown on that path is read and written as gfm. A render mismatch leaves the input unchanged and warns on stderr. Editors, wasm, and LSP stay native. Check formatting without modifying (for CI):

snapper --check paper.org paper.tex notes.md

Limit line width (wrap long sentences at word boundaries):

snapper --max-width 80 paper.org

Break after independent-clause punctuation (comma, semicolon, colon, em dash). With the default unlimited width this inserts a newline after every such mark that already has whitespace after it:

snapper --clause-breaks paper.org

With --max-width set, overflowing sentences prefer those marks. A one-clause sentence stays one line. Split before a lowercase word after a terminator (pass. pytest becomes two lines). Abbreviations such as e.g. and vs. still join:

snapper --lowercase-starts paper.md

Preview changes as a unified diff before committing:

snapper --diff paper.org

Compare two versions at the sentence level (whitespace reflow produces zero diff):

snapper sdiff paper_v1.org paper_v2.org

Watch files and auto-reformat on save:

snapper watch '*.org' 'sections/*.tex'

Initialize a project (generates config, pre-commit, gitattributes):

snapper init

MCP server (AI assistants)

Published snapper / snapper-fmt binaries include the MCP server (mcp is a default Cargo feature). Start the stdio server:

snapper mcp

Agents should call snapper MCP (format_text) or the snapper CLI instead of applying sembr.org / sembr/skills wrapping by hand. format_text accepts clause_breaks, range (start / end, 1-indexed inclusive), and max_width (default 0). From source with --no-default-features, rebuild with MCP:

cargo install snapper-fmt --features mcp

Tools: format_text, detect_format, check_formatting, split_sentences. Configuration guide (org source in-tree): docs/orgmode/howto/mcp-integration.org; HTML docs: https://snapper.turtletech.us/docs/howto/mcp-integration/ .

Supported formats

Format Extensions Structure / code handling
Org-mode .org Drawers, tables, keywords; #+BEGIN_SRC comment reflow
LaTeX .tex, .latex Preamble, math; minted and lstlisting comment reflow; Piton / \piton
Markdown .md, .markdown Front matter, HTML; fenced blocks comment reflow when configured
RST .rst Directives, literals; .. code-block:: comment reflow
Plaintext .txt (none; all text treated as prose). Unknown extensions are refused unless --format is set

Pre-commit hook

- repo: https://github.com/TurtleTech-ehf/snapper
  rev: v0.11.10
  hooks:
    - id: snapper

Emacs (Apheleia)

(with-eval-after-load 'apheleia
  (push '(snapper . ("snapper" "--native" "--format" "org")) apheleia-formatters)
  (push '(org-mode . snapper) apheleia-mode-alist))

VS Code

Install TurtleTech.snapper from the VS Code Marketplace. The extension uses the built-in LSP server for format-on-save, range formatting, diagnostics, and code actions.

Neovim

With lazy.nvim (rocks support):

{
  "TurtleTech-ehf/snapper",
  ft = { "org", "tex", "markdown", "rst" },
  config = function()
    vim.opt.runtimepath:append(
      vim.fn.stdpath("data") .. "/lazy/snapper/editors/nvim"
    )
    require("snapper").setup()
  end,
}

Or with rocks.nvim:

:Rocks install snapper.nvim

Vim

Plug 'TurtleTech-ehf/snapper', { 'rtp': 'editors/vim' }

This provides formatprg support for automatic formatting with the gq operator.

Obsidian

Development preview; not listed in Community Plugins. The WebAssembly plugin source lives in editors/obsidian and is available for development builds only.

Microsoft Word

Development preview; not published in AppSource. The WebAssembly add-in source and sideloading instructions live in editors/word.

Git smudge/clean filter

Auto-format on commit, transparent to collaborators:

git config filter.snapper.clean "snapper --native --format org"
git config filter.snapper.smudge cat

Then add to .gitattributes:

*.org filter=snapper

Vale integration

snapper ships a vale style package for editor hints. Add to your .vale.ini:

StylesPath = /path/to/snapper/vale
[*.org]
BasedOnStyles = snapper

For precise CI checks, use snapper --check directly.

Project config

Drop a .snapperrc.toml in your project root:

extra_abbreviations = ["GROMACS", "LAMMPS", "DFT"]
ignore = ["*.bib", "*.cls"]
format = "org"
max_width = 0
clause_breaks = false

[latex]
verbatim_envs = ["Verbatim"]
structure_envs = ["algorithm", "comment"]
verbatim_commands = ["Verb"]

Missing [latex] keys keep the built-in minted/lstlisting/verbatim/comment/Piton, equation/figure, and verb/lstinline/spverb/Verb/piton lists. snapper walks up from the current directory to find it.

Documentation

Build the docs site with:

pixi run docbld

Development

Key dependencies

  • Clap 4 (derive): CLI argument parsing
  • unicode-segmentation: UAX #29 sentence boundaries
  • regex: Abbreviation and format pattern matching
  • textwrap: Optional line width limiting
  • thiserror: Typed error handling

Conventions

We use cocogitto via cog to handle commit conventions.

Readme

Construct the readme via:

./scripts/org_to_md.sh readme_src.org README.md

License

MIT.

Metadata

Release files for snapper-fmt 0.11.10

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for snapper-fmt 0.11.10
File Size Uploaded
snapper_fmt-0.11.10.tar.gz 523.8 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for snapper-fmt 0.11.10
File
snapper_fmt-0.11.10-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
snapper_fmt-0.11.10-py3-none-manylinux_2_28_aarch64.whl Python 3 none Linux glibc 2.28+ ARM64 Details
snapper_fmt-0.11.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details
snapper_fmt-0.11.10-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
snapper_fmt-0.11.10-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details

Total release size: 85.5 MB

Release files / snapper_fmt-0.11.10.tar.gz

Download URL snapper_fmt-0.11.10.tar.gz
Size 523.8 kB
Tags Source
SHA-256 checksum
How to use checksums
cb13587c7d05bb331a60847566ad7c12217904ad5138e7c93d98ef96af219585
BLAKE2b-256 checksum
How to use checksums
1947cc5ea7a3cbd25507f11b773e4be2a61d2092fe8ea31ffa2472fd8d245319
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release files / snapper_fmt-0.11.10-py3-none-win_amd64.whl

Download URL snapper_fmt-0.11.10-py3-none-win_amd64.whl
Size 18.1 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
706d6038e69b2aa45d63389f29cb17c34d5ee440a146b9fc89861bc3dce2c20d
BLAKE2b-256 checksum
How to use checksums
a1af311841b4e93ec81a9f260cf0f0eaac76d7b5161e570e1eba9a97dc301fc0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release files / snapper_fmt-0.11.10-py3-none-manylinux_2_28_aarch64.whl

Download URL snapper_fmt-0.11.10-py3-none-manylinux_2_28_aarch64.whl
Size 16.2 MB
Tags Linux glibc 2.28+ ARM64 Python 3
SHA-256 checksum
How to use checksums
1652072407e0ec935c2d49dbd12dc5efc45d820622658843d68f68312fdf7d3c
BLAKE2b-256 checksum
How to use checksums
6213f19f4b655bbecbc7a6eda991e4a5d789c9a57d90db2063e6d2be8bc47af6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release files / snapper_fmt-0.11.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL snapper_fmt-0.11.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 17.7 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
29a602e1c04a17fa78056615de60791490e1c16a7c7a3f0d6f1053dea820292f
BLAKE2b-256 checksum
How to use checksums
8c2fb1850fb953e1df041e395e4d8bb555267db0c665c4a79bdd52223ec5432a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release files / snapper_fmt-0.11.10-py3-none-macosx_11_0_arm64.whl

Download URL snapper_fmt-0.11.10-py3-none-macosx_11_0_arm64.whl
Size 15.9 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
a36e2dc8b6324923954a981287e38e64eb2932dc294a1990c1371a9e2120ccc8
BLAKE2b-256 checksum
How to use checksums
a9b51e4af7bae31aa70c5314aab9c0ab49ed124322fa850303347b596f151e20
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release files / snapper_fmt-0.11.10-py3-none-macosx_10_12_x86_64.whl

Download URL snapper_fmt-0.11.10-py3-none-macosx_10_12_x86_64.whl
Size 17.0 MB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
ebf5a0bda176bc16b360b635c4d2df055e6bd0569a05d9cceab99dd05f4d78ee
BLAKE2b-256 checksum
How to use checksums
12bbfe34010f60b7ce7c4c04418709953ea9d2c8ea3a4dc488791fa7dcda7dfa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.11.10 This release

6 release files

0.11.7

6 release files

0.11.6

6 release files

0.11.5

6 release files

0.11.4

6 release files

0.11.3

6 release files

0.11.2

6 release files

0.10.0

6 release files

0.9.1

6 release files

0.9.0

6 release files

0.8.1

6 release files

0.8.0

6 release files

0.7.9

6 release files

0.7.8

6 release files

0.7.7

6 release files

0.7.6

6 release files

0.7.5

6 release files

0.7.4

6 release files

0.7.3

6 release files

0.7.2

6 release files

0.6.0

6 release files

0.4.0

6 release files

0.3.2

6 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page