stilyagi df12 · deterministic prose analysis
§ 01 · The case

Why Stilyagi.

Existing prose tools fall into four weak camps. Each solves part of the problem by giving up on another. The document below is an argument for a fifth camp — one that keeps structural awareness, programmability, determinism, and source-fidelity without cheating on any of them.

I-IV
§ The four weak camps

Everything almost works.

I

Vale-like tools

Understand structure — but the rule model is constrained by declarative YAML, canned check families, and a deliberately limited extension surface.

Structural, but capped
II

Ad-hoc regex

Cheap to write. Poor structural awareness, poor fix safety, poor false-positive behaviour once text lives inside headings, tables, docstrings, or mixed markup.

Dumb in structure
III

Formatter-adjacent

Catch layout and syntax-adjacent issues. Not designed to express editorial policy, terminology rules, or documentation structure constraints.

Wrong register
IV

Broad NLP toolkits

Flexible — but no source-faithful spans, no repository-friendly CLI, no suppression semantics, no stable lint diagnostics out of the box.

Too much work
The Style Hunter — a suited figure with magnifying glass inspects prose

The style hunters.

Rules are written in expressive Python, operating on typed wrappers, not raw JSON dictionaries. Inspired by astroid for node navigability, enabling parent/child traversal and stable properties. Target explicit descriptors like RegionTarget(kind="heading") rather than relying on abstract string matching.

The pain isn't "English is hard."

The target users of Stilyagi are engineers and technically literate writers maintaining documentation inside source repositories. Their pain is not that English is hard.

Their pain is that documentation policy is real, files are structured, CI needs determinism, and the current linting surface is either too dumb to encode the intended policy, or too awkward to continue encoding it.

The value is precise.

Against Vale, Stilyagi offers Python-authored rules over a typed runtime model instead of YAML plus regex plus fixed rule families. Against in-house regex scripts, it provides structural parsing, stable spans, fix planning, suppression semantics, and cacheable behaviour. Against formatter-adjacent tools, it targets prose policy rather than code layout. Against raw spaCy or NLTK, it adds the extraction, diagnostics, configuration, and CLI contracts that fit normal software engineering workflows.

It is weaker, deliberately, in three places.

It will never match a Rust-only rule engine for raw execution speed. It deliberately trusts plugin code, and so cannot truthfully promise sandboxing. It inherits Python packaging complexity for third-party rule packs. These are acceptable costs. The product wins or loses on expressiveness, debuggability, and adoption — not on shaving the last few milliseconds off a single regex rule.

§ 03 · Who for

Five personas, one product surface.

The same tool must feed the CI pipeline, the doc engineer, the polyglot developer, and the agent. Stilyagi defines its contracts so a single machine interface satisfies all of them without growing a second rule engine.

Persona Cares about Ignores
Doc & tooling engineers Deterministic CI, rule packs, SARIF, stable spans, repo-wide policy. Fancy linguistic research features that slow CI down.
API & SDK docs teams Markdown structure, terminology, heading policy, code-adjacent prose, per-file ignores. Academic NLP purity.
Python & Rust developers Docstring summary rules, comment extraction, source-owner metadata, safe fixes. Deep support for every markup dialect on day one.
Technically opinionated solo devs Fast CLI, expressive Python rules, debug visibility, local configuration. Enterprise plugin governance.
Agentic & CI environments JSON output, stdin support, exit-code discipline, predictable cache and suppression behaviour. Interactive UI affordances.
04
§ Non-negotiables

Eight commitments the engine holds.

§ 01

Source-faithful

Every diagnostic and every applied edit maps back to original bytes. Synthetic spans cannot be written to.

§ 02

Deterministic

Rules sort by pack then code. Files sort by normalised path. The same input yields the same diagnostics, always.

§ 03

Offline

Core functionality never reaches the network. No model auto-downloads. No phone-home. CI works on isolated runners.

§ 04

Programmable

Rules are real Python. Typed wrappers. Capability declarations. No YAML ceiling, no bespoke DSL, no recompile.

§ 05

Structural

Regions, not bytes. Owners, not guesses. Headings, tables, docstrings, and comments — each a first-class extraction target.

§ 06

Conservative fixes

Safe, unsafe, and manual are distinct classes. Safe fixes stay narrow. Overlapping non-identical edits fail loudly.

§ 07

Honest about trust

Plugins are trusted code. The docs say so. The CLI help says so. No claims of sandboxing we cannot keep.

§ 08

Debuggable

dump-ir is not an afterthought. Maintainers can always ask, "what did the extractor see, and what did the rule receive?"

§ 05 · Rejected alternatives

What we considered, and retired.

A design document earns its authority by naming the roads it did not take. Each of these was considered at length; each was rejected for reasons recorded below.

Pure PythonRust-only engineVale wrapperRaw-AST rulesLLM assistNo IR

☞ Five no's

  1. Pure Python parsing. Makes source-fidelity and future editor performance worse at the exact point where Stilyagi must be strongest.
  2. Rust-only rule engine. Cripples the rule-authoring story. The whole point is letting engineers write real rules without a bespoke DSL.
  3. Vale-compatible wrapper. The requirement is wholesale replacement. Carrying Vale packaging would preserve the wrong constraints.
  4. Direct raw-AST rule authoring. Makes simple structural rules possible, but text-oriented rules would repeatedly flatten markup and rebuild context.
  5. Heavier LLM-assisted analysis. Nondeterministic, expensive, hostile to offline CI. Belongs outside the core.
"Rules govern regions, not raw bytes."— From the maintainer's rubric