llm-scrub
Zero-dependency scrubbers for LLM chat output. Weak models leak backend
scaffolding into the text shown to the user — JSON state-op fences, injected
=== … === context blocks, and English "tool preamble" meta-narration.
llm-scrub strips that noise deterministically, using pure string/regex
logic instead of relying on the model to obey a prompt.
- No dependencies. Pure standard library (
json,re). - Deterministic. No model call, no network — a plain
str -> strtransform. - Conservative. Tuned to under-strip rather than over-strip: legitimate
fenced code blocks, JSON data, markdown tables, and
===dividers survive. - Idempotent.
scrub(scrub(x)) == scrub(x).
Install
pip install llm-scrub
Requires Python 3.10+.
Quickstart
from llm_scrub import scrub
raw = (
"好,开始输出。\n\n"
"=== 时间线检索锚点 ===\n"
"当前时间:序章 · 站台\n\n"
"林夕睁开眼睛,废墟在昏黄的天光下铺展开来。\n\n"
'```json\n[{"op": "set", "path": "world.location", "value": "废墟"}]\n```\n'
"Let me mark the anchors now."
)
print(scrub(raw))
# 林夕睁开眼睛,废墟在昏黄的天光下铺展开来。
scrub chains the three scrubbers in the canonical order. Call them
individually when you only need one:
from llm_scrub import (
strip_json_state_ops,
strip_meta_tool_preamble,
strip_leaked_scaffold,
)
strip_json_state_ops('战斗结束。\n```json\n{"op": "append", "path": "bag", "value": "刀"}\n```')
# '战斗结束。'
strip_meta_tool_preamble("他转身离去。\nLet me update the anchors now.")
# '他转身离去。'
strip_leaked_scaffold("她走进废墟。\n\n=== 相关原文片段 ===\n某段原文\n\n她捡起刀。")
# '她走进废墟。\n\n她捡起刀。'
API
| Function | Signature | Removes |
|---|---|---|
scrub |
scrub(text: str, *, extra_headers=None) -> str |
All three, chained in the canonical order. |
strip_json_state_ops |
strip_json_state_ops(text: str) -> str |
JSON state-op fences — fenced (```json […] ), un-fenced bare [{"op":…}], and truncated/unclosed ops left by a cut-off response. |
strip_meta_tool_preamble |
strip_meta_tool_preamble(text: str) -> str |
A leaked English "tool preamble" sentence at the tail (e.g. "Let me mark the anchors now."). |
strip_leaked_scaffold |
strip_leaked_scaffold(text: str, *, extra_headers=None) -> str |
Whole === … === backend scaffold blocks (retrieval anchors, world-line summaries, etc.), plus a trailing "begin output" reasoning preamble. |
LEAKED_SCAFFOLD_KEYS is the built-in tuple of scaffold header markers; pass
your own via extra_headers to extend it.
What it strips
1. JSON state-op fences. Some pipelines let the model emit state changes as JSON. Those blocks must never reach the reader:
你推开门,走了进去。
```json
[{"op": "set", "path": "player.location", "value": "地窖"}]
```
→ 你推开门,走了进去。 — including malformed and truncated (streamed-and-cut)
variants. A fenced JSON block that is not ops (a plain object or array of
data) is preserved, so legitimate code examples survive.
2. Leaked tool preamble. Before a native tool call, a model may blurt one line of meta-narration meant for itself:
…晨光无声流转。The scene has progressed naturally. Let me mark the anchors that have been satisfied through our gameplay.
Only a trailing, unquoted, predominantly-English segment matching a preamble phrase is removed. A character's English dialogue inside quotes is never touched.
3. Leaked scaffold blocks. Weak models sometimes dump the backend's invisible context straight into the prose:
=== 时间线检索锚点 ===
当前时间:序章 · 站台
待确认跳跃:无
These headers are fixed strings the backend injects; normal narrative never emits them verbatim, so the whole block is removed with zero collateral damage. Extend the header list for your own backend:
scrub(text, extra_headers=("我的自定义脚手架",))
Design: under-strip, never over-strip
Every scrubber is tuned to leave the text alone when in doubt:
- Fenced/bare JSON is only stripped when it parses and carries state-op
markers (
op/path/question). Other JSON is preserved. - A trailing English segment is only stripped when it is outside quotes and matches a known tool-preamble phrase.
- A
=== … ===line is only stripped when its inner text matches a known scaffold header — a=== 序章 ===divider or a markdown setext underline is left intact. - If stripping would empty the text (a whole turn of pure leakage), the original is returned rather than blanking the message.
License
MIT — see LICENSE.
Acknowledgements
Extracted from the RPG Roleplay platform (https://github.com/felixchaos/rpg-roleplay-platform).
Metadata
Release files for llm-scrub 0.1.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 | Provenance | Actions |
|---|---|---|---|---|
| llm_scrub-0.1.0.tar.gz | 16.6 kB | With provenance | Details for llm_scrub-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| llm_scrub-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for llm_scrub-0.1.0-py3-none-any.whl |
Total release size: 28.0 kB
Release files / llm_scrub-0.1.0.tar.gz
| Download URL | llm_scrub-0.1.0.tar.gz |
|---|---|
| Size | 16.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
628103944b375534a68d8d6d7bb55b49433423b50e2e49f1a10366a70e65efa5
|
|
BLAKE2b-256 checksum How to use checksums |
ca04d9aedc02ed157e26140babded8b57b052c4903fd31d0b6d55a91120d4c84
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jul 14, 2026.
Transparency logRelease files / llm_scrub-0.1.0-py3-none-any.whl
| Download URL | llm_scrub-0.1.0-py3-none-any.whl |
|---|---|
| Size | 11.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1675d1c8cbd135574390861ba377a1d9962dd984acec2d43d58d97840c9bc03e
|
|
BLAKE2b-256 checksum How to use checksums |
ef51ebc39c23d8c8d462422b3bc7e861df330462f06026119cd9ca784bde0322
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jul 14, 2026.
Transparency logSecurity for llm-scrub 0.1.0
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for llm_scrub-0.1.0.tar.gz
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 Jul 14, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.