github guillaumemeyer/watermarks-remover v0.5.0
v0.5.0 — service & Docker distribution, HTTP API, and verification harnesses

3 hours ago

v0.5.0 is the biggest release yet: watermarks-remover is now a full service you can self-host — a stdlib HTTP API, Docker images on GHCR, a one-command compose stack, and two new optional research harnesses (MarkDiffusion for images, MarkLLM for text) for verifying that your pipeline actually clears a mark.

The skill is now a thin, code-free client that drives the machinery over HTTP, so your agent host doesn't even need Python. Everything from v0.4.0 keeps working — the CLIs are all still there and remain the primary interface for local use.

Service & Docker distribution

  • Skill/service split: the skill (skills/remove-ai-marks/) is now a code-free remote client over HTTP. All implementation moved to service/scripts/ and runs behind server.py, a stdlib HTTP entrypoint (/health, /inspect, /clean, /capabilities)
  • HTTP service: server.py exposes the cleaning pipeline over JSON/base64 with hardening that mirrors the CLIs — size caps, binary guard, atomic writes, loopback-only bind by default, and optional WATERMARKS_SERVER_API_KEY bearer auth
  • OpenAPI: GET /openapi.json serves a dynamically generated OpenAPI 3.0.3 spec, built from the route table + live config so it never drifts from the real endpoints; CI validates it with openapi-spec-validator
  • Core Docker image: full cleaning service with exiftool / qpdf / c2patool preinstalled. Any CLI stays runnable by overriding the command — docker run watermarks-remover /app/scripts/clean_file.py ... just works
  • Docker / compose: compose.yaml brings up the whole infra — core always, markllm / markdiffusion behind profile: harness, ctrlregen / synthid behind profile: heavy as local-only builds. Services are prefixed wr-, one-shot CLIs exit cleanly under compose up, and make compose-check validates the running stack
  • GHCR publishing: .github/workflows/release-images.yml publishes core, markllm, and markdiffusion images automatically on every v* tag. ctrlregen / synthid are never published (upstream licensing)
  • Env configuration: .env.example + service configuration guide; docker compose auto-loads .env; .env is gitignored deny-by-default so your keys stay local
  • Repo hygiene: .gitignore and service/.dockerignore are now deny-by-default — only explicitly allowed paths can be committed or sent in a build context (image contexts only ship service/scripts/, which is all the Dockerfiles COPY)
  • Tests: tests/test_http_server.py (13 cases) for the HTTP service; all suites re-pointed at service/scripts/

MarkDiffusion image-watermark harness (optional)

  • New optional harness wrapping the external THU-BPM/MarkDiffusion toolkit (Apache-2.0): markdiffusion_harness.py with watermark / detect / purify subcommands for nine image schemes (Tree-Ring, Ring-ID, ROBIN, WIND, SFW, Gaussian-Shading, GaussMarker, PRC, SEAL)
  • clean_image.py --remove-pixel diffusion runs the MarkDiffusion DiffusionPurification regeneration attack as an alternative pixel-removal engine (conservative strength 0.3 default — it's blind regeneration, so it drifts content more than CtrlRegen)
  • setup_markdiffusion.sh bootstrap (PyPI pin 1.0.2, --checkout for an editable clone at a pinned commit) + Dockerfile.markdiffusion + Makefile targets
  • Mock-based tests (no torch in CI) and a references/markdiffusion.md doc
  • Caveats documented honestly: same-scheme-only verification (not a vendor-detector oracle) and the blind-regeneration drift trade-off

MarkLLM text-watermark harness (optional)

  • New optional harness wrapping the external THU-BPM/MarkLLM checkout (Apache-2.0): detect_text_watermark.py with detect / watermark subcommands for KGW and SynthID schemes
  • rewrite_text.py --markllm-scheme runs before/after detection around a Layer B rewrite (env-gated; reports cleared) — so you can prove a mark clears under your rewrite
  • setup_markllm.sh bootstrap + Dockerfile.markllm + Makefile targets
  • Hardening: --offline cache-only model loading (zero HF egress, no remote code), 1 MiB config cap, optional WATERMARKS_MARKLLM_RLIMIT_AS on the rewrite subprocess, pinned torch, and clone-SHA verification in the Dockerfile
  • Mock-based tests (21 cases) — no torch in CI

Fixes and polish

  • Layer B: rewrite_text.py now sends reasoning_effort: "none" by default for openai-compatible backends (--reasoning-effort / WATERMARKS_REWRITE_REASONING_EFFORT). Reasoning models like deepseek-v4-flash otherwise burn ~100s of chain-of-thought on a one-line rewrite (9,894 vs 12 completion tokens!)
  • Fix markllm image build: requirements-markllm.txt pinned tokenizers==0.23.1, which conflicts with transformers==5.15.0 (caps tokenizers<=0.23.0; no 0.23.0 release exists) — now pinned tokenizers==0.22.2; torch moved to the CPU wheel index so the image is CPU-only like Dockerfile.markdiffusion
  • Fix ctrlregen image build: the 2023-era research pins ship no Python 3.14 wheels, so the base image is now python:3.11-slim (digest-pinned, multi-arch)
  • Fix harness images at runtime: Dockerfile.markllm and Dockerfile.markdiffusion never copied common.py into /app (pre-existing bug) — added
  • WebP: stdlib-only inspection and metadata cleaning for RIFF C2PA, XMP, EXIF, and ICC profile chunks (#37)
  • Filename sanitization: the HTTP service refuses unsafe client-supplied output names
  • Markdown frontmatter: cleaner no longer crashes on or leaks nested AI keys (#25)
  • Text tools refuse binary input; --force-text overrides (#24)
  • --json no longer suppresses the residual-signal exit code (#30)
  • inspect_file prints the filename in its output (#50)
  • Mixed-case CMS generator meta tags preserved (#42)
  • Layer A: preserve load-bearing script invisibles, strip PUA (#38, #52); preserve script joiners, flag emoji and Arabic Cf marks (#28)
  • Website audit hardened against SSRF and gzip bombs (#49)
  • SECURITY.md now only references the private advisories channel (#51)
  • Windows: PowerShell ports of the setup bootstraps (#40)
  • Docs: stars/forks shields, MarkLLM reference, pull request template, Docker CLI + API deployment plan

A big thanks to everyone who filed issues, reviewed PRs, and ran the harnesses — this release is a team effort. 🎉

Full changelog: README

Don't miss a new watermarks-remover release

NewReleases is sending notifications on new releases.