Sieve Redact v0.5
A command-line tool that removes sensitive information from documents — deterministically, while preserving byte-for-byte integrity of everything else.
English | 日本語
💡 Concept
Personal information in resumes, reports and logs is converted into a second file that is safe to publish and share.
- Deterministic — Same input plus same rules always produces the same
output. Character selection in
noiseis derived from SHA-256; it depends on nothing else — not on the environment, the clock, or any RNG. - Byte-for-byte integrity — Bytes outside a match are left untouched,
down to the last byte. CRLF line endings survive. Integrity is verified
mechanically before output;
--strictrefuses to write on failure (exit code 3). - No guessing — The user specifies what is sensitive. The engine never guesses.
- Receipts — The receipt records the facts of processing (positions,
lengths, modes, hashes) but never the sensitive body itself. Even
"no pattern remains" is reported as a measurement
(
pattern_appearance_in_output), not a promise.
The name refers to a sieve: drop only what is specified, and leave everything else unharmed, byte for byte.
Companion tool to Sieve Lens (observation of invisible content) — Lens observes, Redact masks.
🧩 The Sieve Series
Sieve is a family of deterministic, zero-dependency engines that share the same design principles (deterministic output, no telemetry, fully local) — each engine observes or masks one specific risk, and they compose:
| Package | Role | Connects to |
|---|---|---|
| sieve-core-engine | Base logic / plugin host for the ecosystem | — |
| sieve-lens | Observes invisible content & hidden prompts in documents | → redact via --from-lens |
| sieve-scope | Detects structurally similar code pairs | — |
| sieve-referee | Detects paraphrased / reused text pairs | — |
| sieve-redact | Masks sensitive regions (text & PNG) with receipts | ← lens, → tray |
| sieve-tray | Desktop front-end that routes files to the right engine | ← all engines |
Observation → masking in one pass: Lens finds what a human can't see, Redact removes it with a receipt that proves nothing else changed.
🔥 Features
Six redaction modes
| MODE | Operation | Content |
|---|---|---|
delete |
remove the region | empty string |
mosaic |
fill per character | █ repeated for the original character count |
label |
numbered labels | prefix (default [REDACTED]) + sequence number |
noise |
same-class replacement | picked deterministically within the same character class (hiragana / katakana / kanji / upper / lower / digit) |
decor |
wrap | ARG + original + ARG |
replace |
bulk replace | ARG |
Built-in matchers (--builtin)
| NAME | Target |
|---|---|
postal-jp |
Japanese postal codes NNN-NNNN |
phone-jp |
Japanese phone numbers (090-… / 03-… / 050-… / 0120-… / 4-digit area codes 01XX-07XX) |
email |
Email addresses (ASCII) |
chars |
All occurrences of given codepoints (U+200B,U+00AD form) |
Image masking (--region)
PNG images (8-bit RGB/RGBA, non-interlaced, non-animated) are masked by
explicit regions: --region x,y,w,h:MODE[:ARG] (repeatable; overlapping
regions are discarded in declaration order; zero-area or out-of-bounds
regions are usage errors; --rule cannot be combined with --region).
| MODE | Effect |
|---|---|
delete |
opaque white fill |
mosaic |
block average over all channels (blocks align to the region origin; ARG = block size, default 8) |
noise |
per-pixel deterministic replacement — SHA-256(img:x:y:R,G,B) drives the new RGB; alpha is kept, so semi-transparent pixels keep their visibility (content changes, visibility does not) |
label |
black band with [REDACTED]n (bundled bitmap font) |
decor |
2px border in the ARG color (RRGGBB hex) |
replace |
ARG text drawn on a white fill (bundled bitmap font) |
Image receipts set byte_integrity_verified to null (not applicable —
PNG re-encoding changes file bytes structurally) and report pixel
integrity outside every region as pixel_integrity_verified; --strict
exits 3 when it fails. File metadata (EXIF etc.) is always dropped on
save — a privacy-friendly default by design. Output bytes are
deterministic across platforms and pinned in CI (with Pillow 12.3.0;
future Pillow updates may change encoded bytes, never pixels).
Word-unit matching (+ prefix)
太郎:label also matches the 太郎 inside 田中太郎; 太郎:+label
matches only at word boundaries (adjacent characters of the same class, or
both alphanumeric, cause rejection).
Config files and Lens integration
--config rules.cfg: load rules from a file (rule <spec>/builtin <spec>line format).--from-lens catalog.json: generate masking rules from an observation catalog (JSON) produced by Sieve Lens. Invisible characters become deletions; look-alike letters (Cyrillic/Greek → Latin) become replacements based on thetwinfield.
💻 Quick start
git clone https://github.com/neguseatama/sieve-redact.git
cd sieve-redact
# Mosaic a name, label phone numbers
python sieve_redact.py in.txt -o out.txt \
--rule "田中太郎:mosaic" \
--builtin phone-jp:label \
--receipt receipt.json
Example receipt (stdout) — in.txt contains x秘密y, run with
--rule "秘密:delete":
Sieve Redact v0.5 — レシート
入力: 8 バイト -> 出力: 2 バイト
redact 件数: 1
#1 rule=1 matcher=literal mode=delete pos=1..7 len=6B -> 0B sha256=062a2931da68...
他バイト完全性: 検証済み
出力内パターン残留: none
The sensitive body never appears in the receipt — hashes only. In
image mode (--region) byte_integrity_verified is null (not
applicable) and pixel integrity is measured by
pixel_integrity_verified instead.
Integration with Sieve Lens
# (1) Lens produces an observation catalog
python -m sieve_lens_ext.redact_bridge input.txt catalog.json
# (2) Redact masks everything
python sieve_redact.py input.txt -o clean.txt --from-lens catalog.json
🔬 Determinism guarantees
Character selection in noise is fully determined by:
char = POOL[ SHA-256("<pattern>:<byte_offset>:<original char>").digest()[0] % len(POOL) ]
No seed. No environment dependence. Same input, same output, always. The bundled tests verify exact agreement with this formula by recomputation.
Overlapping matches are resolved deterministically as well: rules are tried in declaration order, each rule scans leftmost-first, later matches that overlap a confirmed region are discarded, and confirmed regions are applied in ascending order of position.
🔬 Tests
python -m unittest discover -s tests -v
113 tests (five modes, built-in matchers, word-unit matching, config files, Lens integration, CLI boundaries). No additional dependencies.
⚠️ Known limitations
- No regex — patterns are literal, exact-match strings only
- No case-insensitive matching — matching is case-sensitive
- No automatic sensitive-data detection — the user specifies what is sensitive (by design)
- Text and PNG images — PDF and Office formats are not supported; image masking is PNG-only (8-bit RGB/RGBA) and JPEG is explicitly out of scope; PDF masking is out of scope (observation is Sieve Lens's domain)
- Full-width digits and non-ASCII hyphens are out of scope for postal/phone
- 4-digit area codes starting with 08/09 (except
0800) and short numbers such as 117/104 are out of scope forphone-jp— match them explicitly with--rule
📄 License
MIT. See LICENSE.
👤 Author
- Kai IWASAKI
Metadata
Release files for sieve-redact 0.6.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 | |
|---|---|---|---|
| sieve_redact-0.6.0.tar.gz | 37.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sieve_redact-0.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 58.5 kB
Release files / sieve_redact-0.6.0.tar.gz
| Download URL | sieve_redact-0.6.0.tar.gz |
|---|---|
| Size | 37.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
999e57e907a7442b0abd01122bc0e6e4ee7cd1ac00d5d827a2cb2c6d64500a46
|
|
BLAKE2b-256 checksum How to use checksums |
98d9af8166ab4c265fd05aa54d384dd20b16522b74bd3dd313736cbcdb91e024
|
| 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 9, 2026.
Transparency logRelease files / sieve_redact-0.6.0-py3-none-any.whl
| Download URL | sieve_redact-0.6.0-py3-none-any.whl |
|---|---|
| Size | 20.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c9456bed63c92e66e8c2cc20ac894d3f4c3726f7f34be4a9f06291ee16928ba5
|
|
BLAKE2b-256 checksum How to use checksums |
f09fd1caf7de1fe76da07ba9a34f7fa61dd5b0c17290bc21f0229af71dfc498f
|
| 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 9, 2026.
Transparency log