No server. No API key. No network. Five agent skills over eight deterministic checkers. Same input, same findings, every time.
An LLM asked to proofread a text reads all 9,000 words into its context, forgets the middle, and invents a citation error on page 4. This doesn't. The checkers find the problems and hand over line, column, and a short excerpt; the agent judges and reports, and never reads the manuscript to find anything.
Install
Claude Code plugin
/plugin marketplace add domrice/prose-preflight
/plugin install prose
Any other harness (Cursor, Codex, Copilot, Gemini, Windsurf, …)
npx skills@latest add domrice/prose-preflight
Both resolve the package from PyPI — no repo on disk, no paths in SKILL.md. Needs
uv; it supplies its own Python ≥ 3.11.
The five skills
/prose-init once per project — writes the contract
/prose-preflight check and report ┐
/prose-deepread read end to end and report ┘ never edit
/prose-draft write new prose ┐
/prose-edit apply findings you picked ┘ only with your yes
prose-initinterviews you once — what you are writing, who reads it, which venue and style, which terms and acronyms — and writesprose-preflight.yaml. The other four read it.prose-preflightruns the checkers and diagnoses the result: what the counts mean, and a verdict on everyseverity: reviewfinding —keep,soften, orcut, with a rewrite. A checker can see a hedge; only the agent can weigh it against your argument.prose-deepreadis the opposite: it reads the manuscript end to end for what no regex reaches — claims the results do not support, terms used before they are defined, sections that do not deliver what their heading promises, passages that can go. Expensive, so it runs only when you ask for it by name.prose-draftis the only one that writes new text. Give it content — bullets, notes, numbers — and it proposes an outline, waits for your yes, drafts against the contract, and inserts under the heading you named. No contract, no draft; no content, only questions.prose-editcloses the loop: it applies the findings you picked out of a report, and only those. It reads the paragraph around each finding rather than the file, previews every change before touching disk, and marks what it changed. Areviewfinding is edited only because you named it.
The contract
One file per project, prose-preflight.yaml, holds both halves of your setup. Run
/prose-init once; it writes the file through the tool, so the YAML is serialized and its
keys validated, never hand-typed. A prose-preflight.yaml in the working directory is
picked up automatically.
The contract: block is agent-facing — no checker reads it, but every report carries it,
so the agent judging your hedges knows whether "may indicate" is right for your journal. The
checks: block is the deterministic half.
contract:
document: conference paper
audience: graphics researchers, non-specialist in differentiable rendering
venue: SIGGRAPH — ACM house style, numbered citations
voice: first person plural, past tense for methods, active where possible
guide: PROSE.md # the long-form rules; see below
format: tex # md | tex | txt
checks:
terminology:
terms:
ray tracing: [raytracing, ray-tracing]
signed distance field: [SDF, signed-distance field]
sentence_length:
max_words: 32
structure:
required_sections:
[Abstract, Introduction, Related Work, Method, Results, Conclusion, References]
units:
disabled_rules: [range_dash] # if your venue insists on hyphens
contract.guide points at a Markdown file — PROSE.md by convention, written by
/prose-init beside the YAML. notes: is a scalar, good for a house rule or two;
anything that becomes a list that grows belongs in the guide, under topic headings, one
rule per bullet. prose-draft, prose-edit, and prose-deepread read it and treat it
as part of the contract; where a guide rule and a contract key disagree, the guide is the
more specific statement and wins. prose-preflight deliberately does not read it, so a
routine check never pays for it. A guide that is named but missing stops the two skills
that write.
Keep only what you change; the rest falls back to defaults. Lists are replaced, not appended, and unknown keys are reported on stderr, so a typo never fails silently.
Two lists ship empty, because a wrong entry costs a false positive on every run:
terminology.terms and structure.required_sections. Fill them in and those checks switch on.
Everything a document convention needs lives in YAML. If a new convention would need a code change, that's a bug in the checker.
Checks
| check | flags | severity |
|---|---|---|
vale.* |
grammar, spelling, style — whatever your Vale config says | error/warning |
terminology.variant |
dataset where the config wants data set (opt-in) |
warning |
acronym.undefined |
used without expansion at first use | warning |
structure.missing_section · .section_order |
required sections, absent or out of order (opt-in) | error/warning |
sentence_length.long |
sentences over max_words |
warning |
readability.flesch · .fog |
per section, skipping ones too short to score | warning |
units.space_before_unit · .percent_spacing · .range_dash · .p_value_spacing |
12 mm → NBSP, 5 % → 5%, 3-7 → 3–7, p<.05 → p < 0.05 |
warning |
claim.hedge · .booster |
"may possibly suggest", "clearly demonstrates" | review |
review is not a quieter warning. It is the line between what a script can decide and what
it cannot: whether your evidence carries your claim. Nothing marked review is ever
auto-applied, by the tool or the agent.
Code, math, verbatim blocks, and LaTeX command sequences are blanked before any regex runs — character-for-character, so every offset stays a true source position. Your equations are not prose and are not judged as such.
The full report lands in PREFLIGHT_<file>.md, one per document; only a capped summary goes
through the agent's context. That split is the whole point.
Vale
Vale powers grammar and style and is pinned as a dependency — no
brew install, no manual step. The binary is fetched once on first run and cached; after
that, runs are offline. If that download is blocked (air-gapped, proxy, locked-down CI), the
run emits one vale.unavailable warning and the other seven checkers still report. Vale is
never a hard prerequisite; install it yourself and it's picked up from PATH.
Vale has no LaTeX reader, so a .tex file is handed to it as masked prose — commands,
preamble, math, and verbatim already blanked, line for line — and the alerts still carry true
source positions.
Develop
git clone https://github.com/domrice/prose-preflight && cd prose-preflight
uv sync && uv run pytest
Every checker has a fixture pair in tests/fixtures/: an intentionally flawed document and
the exact set of (check, line) pairs it must produce. Pinning positions is deliberate —
false positives cost more here than misses, since each one burns agent tokens and spends
trust in the report.
Adding a checker is one module exposing check(doc, rule) -> list[Finding] plus one line in
the registry. If it also needs a change to the runner, the design was wrong.
License
MIT
Metadata
Release files for prose-preflight 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| prose_preflight-0.3.0.tar.gz | 62.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| prose_preflight-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 89.4 kB
Release files / prose_preflight-0.3.0.tar.gz
| Download URL | prose_preflight-0.3.0.tar.gz |
|---|---|
| Size | 62.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
51422b50d26e84c017eac576439b1aa710b4313ff617d88d75da31ae46237234
|
|
BLAKE2b-256 checksum How to use checksums |
e190e12653552de07bdea21057b434e8a1999c9ffa9758f86c36d600d2d98a90
|
| 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 Sep 19, 2026.
Transparency logRelease files / prose_preflight-0.3.0-py3-none-any.whl
| Download URL | prose_preflight-0.3.0-py3-none-any.whl |
|---|---|
| Size | 26.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e7c6555b04d4252b36a255f581c964653595429fd6e4a69a471e8706dccab9e1
|
|
BLAKE2b-256 checksum How to use checksums |
a876c3609d87a97a843bf21bdd13377516565220823faac150d050271706c6e2
|
| 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 Sep 19, 2026.
Transparency log