
defluff
io.github.ahmedak由 GitHub 账号 ahmedak 发布v0.1.2更新于 Oct 24, 2026
Deterministic prose linter for LLM text — flags AI slop, filler, buzzwords, hedges, clichés.
概览
一个本地运行的确定性文字检查器,让助手为文本打出 AI 套话、空话和陈词滥调的分数,并管理用于比对的短语表。
- 可以做什么
- 为一段文本计算空话密度,返回被标记的短语及其类别、权重和位置,并给出词表版本哈希和短文本的低置信度标记。向用户级或项目级词表叠加层添加自定义短语,或屏蔽诸如领域术语的短语。完全离线运行,是确定性匹配器,不使用模型也不需要 API 密钥,因此每次运行结果一致。
- 适用场景
- 适合让助手在返回草稿、更新日志或文档前自查其中可删除的空话,也适合用可固定、可复现的套话分数在 CI 中把关生成内容。由于只匹配已知短语表,对识别新出现的流行词帮助有限。
- 运行要求
- 通过 uvx 从带 mcp 扩展的 defluff 包以本地进程方式运行,或安装该包后运行 defluff-mcp 入口。需要 Python;未说明需要 API 密钥、模型下载或网络访问。
安装
在 SourceWeft 中
- 打开 控制台中的 defluff,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
defluff
The deterministic slop check for AI-generated prose. Point it at a changelog, a doc, or an agent's own output and get back the filler phrases to cut — plus a CI exit code and a pinnable score, identical on every run. No model, no API key.
[CI] [PyPI] [Python 3.10+] [License: MIT] [Last commit]
[Fluffy text gets flagged: defluff lints a sentence full of buzzwords and clichés, returning the slop spans and an over-threshold score.]Every flagged span carries no information, so cutting them loses nothing. Clean text, same tool, passes straight through:
[Clean text passes: defluff lints a plain, concrete sentence and returns a 0% slop score.]What makes defluff worth installing over a one-off grep is the engine around the list: bring your own phrases, per-project overlays, and an MCP server your agents pick up with no wiring.
Install
Or on macOS/Linux via Homebrew:
That's it. No model download. No API key. Runs anywhere Python does.
Quick start
MCP server
Exposes three tools so any MCP-aware agent can self-check prose without bespoke wiring — including its own draft, before returning it.
Zero-install via uvx (recommended) — pulls the package and the mcp extra on first run:
Or install it and run the entry point directly:
Published to the MCP Registry as io.github.ahmedak/defluff (see server.json).
mcp-name: io.github.ahmedak/defluff
Common use cases
- Agent self-correction — call
slop_detecton a draft and revise the flagged phrases before returning it. Zero wiring, one session, no second model in the loop. - CI gate on generated content — fail the build when an AI-drafted changelog or doc ships full of "furthermore" and "robust." Deterministic + exit codes + a pinnable lexicon is what an LLM-judge gate can't give you.
- Writing assistant feedback — highlight the exact phrases an editor would cut, instead of a vague "this sounds AI."
- A reward component for fine-tuning — see reward loops for caveats; on its own it's gameable.
Why defluff?
Every "AI detector" tries to classify whether text was AI-generated — a hard, unreliable problem. defluff asks a different question: does this text contain removable filler? That's deterministic, and it's true whether a human or an LLM wrote "at the end of the day."
proselint is the closest prior art — deterministic, no model — but emits yes/no warnings rather than a tunable density score, and isn't built around a list you swap, overlay, or pin.
A grep over a word list gives you raw hits. defluff gives you what you'd otherwise have to build around that list:
- An MCP server — agents self-check with zero wiring.
- Markdown- and code-aware — strips code fences, inline code, and URLs first.
- Whole-word matching —
"foster"won't fire inside"fostering". - A normalized score instead of a hit count — filler density, so one threshold works on a tweet or a 5,000-word doc.
- Overlap handling — "at the end of the day" overlapping "end of the day" counts each word once (longest-match-wins).
- Exit codes, JSON, and char-offset spans — drop into CI, pre-commit, and editor tooling.
- A pinnable lexicon hash — prove the ruler didn't move between runs.
Bring your own slop
One phrase per line (# comments and -/* markers ignored). These layer on top of the built-in defaults and report under a neutral custom category. For real categories and per-phrase weights, use a .json list (see Lexicon overlays).
Ready-made domain packs
List them with defluff packs. High-false-positive terms (e.g. pivot, detox) ship commented-out so they're inert until you opt in. See the packs README.
Batteries-included defaults
~130 curated patterns across five weighted categories, case-insensitive, whole-word matched:
Rhetorical patterns (beyond the list)
Some AI tells are sentence shapes, not fixed phrases — the antithesis: it's not X, it's Y, not just a list but a runtime. A regex pattern layer catches these under a rhetoric category:
Each match counts as one unit toward the score regardless of length. Turning on fragment mode changes the lexicon hash.
[Same sentence run twice: the default catches the compound antithesis; --pack rhetoric also catches the short punchy fragment form.]Python API
SlopReport fields:
Lexicon overlays and versioning
The bundled lexicon is the baseline; layer on top without editing the package:
- User overlay (
~/.config/defluff/) — machine-wide, not committed - Project overlay (
.defluff/at git root) — per-repo, commit it for your whole team
Writes are atomic and cross-process locked; a corrupt overlay is warned and skipped — detect() never crashes.
Every resolved lexicon (bundled + overlays + packs) carries a short content hash, printed on every run (lexicon: 2cc05ba84457) and exposed as SlopReport.lexicon_version. Pass lexicon=defluff.load_lexicon() once and every call scores against the same ruler — pinnable for CI baselines and RL rewards, and auditable since the hash changes if and only if the resolved entry set changes. Each release ships a dated lexicon with a changelog (CHANGELOG.md); ai-vocab is expected to turn over release to release, cliche/hedge/corporate/transition are near-stable.
Reading the output and setting the threshold
- The spans — the exact filler phrases, with category. Deterministic, reliable. Act on these.
- The score —
slop_score= flagged words ÷ total, weighted by category (ai-vocabcounts a little more,transitiona little less).0.20≈ "a fifth of this text is listed filler." Usually0.0–1.0; can edge slightly above on text that's almost nothing but slop. Instead of being a quality quantfier, its just a tripwire that drives the CI exit code.
Pick a threshold based on how filler-dense the text is allowed to be:
The default 0.08 is provisional — hand-chosen, not yet calibrated on a labeled corpus (hence the [threshold provisional] tag). For a hard CI gate, set your own threshold and suppress your domain's vocabulary first (below).
Use in CI
Technical writing — API docs, ADRs, RFCs — legitimately uses words like
robust,scalable,in order to. Suppress your project's domain vocabulary first:Then gate only on the categories you trust, not all five:
Exit code 1 fails the step, 0 passes.
Use with pre-commit
Use in reward loops (experimental)
A deterministic, non-differentiable scalar for filler density can be a small component of a reward mix — but it's gameable alone: a model optimized purely against a fixed phrase list learns to paraphrase the filler rather than remove it. Pair it with a real quality signal (human or LLM judge); we don't yet have a published training run showing it helps.
CLI reference
--category— comma-separated; only spans in those categories count toward the exit-code decision (still reports all hits). Valid:ai-vocab,cliche,hedge,corporate,transition,custom,rhetoric.--lexicon PATH— layers your phrases on top of the defaults..txt/.mdis one phrase per line (lands incustom);.jsoncarries explicit categories and weights.--pack NAMES— comma-separated domain packs.rhetoricis reserved for the pattern pack, enabling the opt-inX, not Yantithesis fragment.
Exit codes for defluff lint: 0 = clean · 1 = slop · 2 = bad input.
Accuracy
defluff is a deterministic matcher, not a trained classifier, so the metric that matters is precision — when it flags something, is it actually removable filler? On a 50-example hand-labeled set (eval/validation.jsonl) spanning clear slop, clean prose, and jargon-as-content traps (e.g. "the robust standard errors", "pivotal trials"), at the default threshold:
Reproduce: python eval/score.py eval/validation.jsonl
Misses are novel buzzwords the lexicon hasn't seen yet (e.g. "operationalize the ideation funnel") — the known limit of a list-based matcher, not noise. Recall on listed filler is 1.00 and will rise as the lexicon grows, but won't reach 1.00 against open-ended novel jargon without a semantic layer.
Caveats: the set is small and labeled by the author — a sanity check on precision, not an independently adjudicated benchmark.
Limitations
- It matches a known list by design — it doesn't understand text. Novel buzzwords are missed; this is the trade for being deterministic, local, and reproducible (no model, no API key, pinnable hash). Pair with an LLM judge if you need semantic detection of novel filler.
- Domain jargon is contextual.
"leverage"in a finance document is real content. Read the flagged spans; suppress false positives withdefluff lexicon rm(adds to an ignore list, doesn't delete from the bundled lexicon). - Span offsets are into the cleaned text. defluff strips code fences, inline code, URLs, and markdown markup before matching, so offsets won't line up with your original document — match on
span.text, not raw offsets, against marked-up source. customis read-only-via-file. Phrases from a--lexiconfile land incustom, butdefluff lexicon add --category customis rejected —addonly takes the five curated categories.- English only in v0.
- Short texts (< 20 words) get
low_confidence: true— the denominator is floored at 20 so one phrase can't read as 100% slop on a two-sentence input.
Contributing
The easiest contribution is adding a missed filler phrase:
- Add it to
src/defluff/data/lexicon-v1.jsonwith the right category pytest— smoke tests catch boundary errors- PR with one or two examples of the phrase in the wild
See CONTRIBUTING.md for code setup and guidelines.
License
MIT
来源:README.md,提交 67c0ef3
工具
0版本历史
1- v0.1.2最新Sep 16, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分