
What watermarks-remover does
watermarks-remover is an agent skill and Python service for inspecting and cleaning AI provenance marks from text and supported file formats. It is intended for privacy, research, and content hygiene on material you own or are authorized to process.
The agent skill is a thin HTTP client. It does not contain the cleaning implementation and does not require Python on the agent host. Instead, it sends work to a separately running service built with the Python standard library.
The project divides its work into three areas:
- Text Layer A: deterministically removes invisible Unicode carriers, exotic spaces, bidirectional controls, and tag characters.
- Text Layer B: uses substantial rewriting to reduce statistical token-sampling watermarks. This is best-effort and may change style or voice.
- File cleaning: removes supported C2PA, EXIF, XMP, document-property, and container metadata from many file types.
No tool can guarantee that a vendor detector will stop identifying content. Keep original files, review every cleaned result, and use the project only on content you own or have permission to process.
Key features and supported formats
The core scripts require Python 3.10 or newer and use only the standard library. Optional tools such as c2patool, exiftool, and qpdf are used when available.
Supported cleaning targets
- Images: PNG, JPEG, WebP, AVIF, HEIC, BMP, GIF, TIFF, and SVG.
- Documents: PDF, DOCX, XLSX, PPTX, EPUB, and ODT.
- Text and web files: HTML and Markdown, including supported metadata, JSON-LD, AI frontmatter keys, and Layer A text marks.
- Media containers: MP4, MOV, M4A, M4V, WAV, MP3, and FLAC.
Unrecognized formats are not cleaned automatically. Text-specific commands also reject binary files and direct you to the general file tools.
Important limitations
Core cleaning does not cover soft-bound C2PA or pure pixel, audio, and video watermarks. PDF cleaning needs qpdf for a structural strip because an incremental metadata edit can leave recoverable bytes. An optional Ghostscript pass can address metadata inside embedded PDF images.
Detection is separate from cleaning. Optional detectors for MarkLLM, keyed-Gumbel, Claude seams, and image SynthID scoring are opt-in and designed to fail softly when unavailable.
Install an agent skill
Clone or download the repository, enter its directory, and run the installer. The following command installs the full service-backed skill for a personal Claude Code configuration:
python3 install_skill.py --skill remove-ai-marks --target claude-codeAvailable installation targets include:
--target claude-codeinstalls under~/.claude/skills/<skill>.--target claude-project --project-dir PATHinstalls underPATH/.claude/skills/<skill>.--target coworkproducesdist/<skill>.zipfor upload through the cloud Skills interface.--target cursorinstalls under~/.cursor/skills/<skill>.
Use python3 install_skill.py --list to list shipped skills. The repository provides the full remove-ai-marks skill and a self-contained, text-only clean-user-facing-text skill. Existing installations are backed up unless you use --force. For live editing from the checkout, add --link.
Install the Claude Code plugin
Claude Code users can install the marketplace plugin directly:
/plugin marketplace add guillaumemeyer/watermarks-remover
/plugin install watermarks-remover@watermarks-removerThe skills then load as /watermarks-remover:remove-ai-marks and /watermarks-remover:clean-user-facing-text. Update the plugin with:
/plugin marketplace update watermarks-removerLink the skill for Grok
mkdir -p ~/.grok/skills
ln -sfn "$(pwd)/skills/remove-ai-marks" ~/.grok/skills/remove-ai-marksStart the service
Run the local HTTP service from the repository:
make serveAlternatively, launch the server script explicitly:
python3 service/scripts/server.py --host 127.0.0.1 --port 8765The default address is http://127.0.0.1:8765. If the service runs elsewhere, set WATERMARKS_SERVICE_URL for the skill. The server binds to loopback by default, which avoids exposing it directly to other machines.
Check that the service is responding:
curl -s http://127.0.0.1:8765/healthThe health endpoint returns an object containing ok and the service version.
Inspect and clean files from the command line
The safest workflow is to inspect a file first, write the cleaned output to a new path, and compare the result with the original.
SCRIPTS=service/scripts
python3 "$SCRIPTS/inspect_file.py" draft.md
python3 "$SCRIPTS/clean_file.py" draft.md -o draft.cleaned.md
python3 "$SCRIPTS/clean_file.py" photo.png -o photo.cleaned.png
python3 "$SCRIPTS/clean_file.py" notes.docx -o notes.cleaned.docxUse inspect_file.py and clean_file.py for both text and binary containers. These commands choose the appropriate supported cleaner based on the file.
Clean Layer A text marks
For plain-text input, inspect invisible and edit-based Unicode carriers with:
python3 "$SCRIPTS/inspect_text.py" draft.mdThen create a cleaned copy and print statistics:
python3 "$SCRIPTS/clean_text.py" draft.md -o draft.cleaned.md --statsLayer A is deterministic and intended to be lossless with respect to the visible prose. Do not pass DOCX, PDF, images, or other binary input to these text commands; use the file commands instead.
Prepare a Layer B rewrite
Statistical text watermarks require rewriting rather than simple character removal. By default, the rewrite command prints a prompt:
python3 "$SCRIPTS/rewrite_text.py" draft.md --backend print-prompt --strength paraphraseLayer B is iterative and best-effort. It can reduce fidelity to the original style and voice. When quality matters more than watermark hygiene, the project recommends using Layer A and file cleaning while preserving the original prose.
Use the HTTP API
The service exposes inspection, detection, cleaning, batch processing, capability discovery, and an OpenAPI specification.
GET /healthreports service health and version.GET /capabilitiesreports available optional tools and backends.GET /openapi.jsonreturns the OpenAPI 3.0.3 specification.POST /inspectreturns the input kind, suspicious status, and report.POST /detectreturns configured detector results.POST /cleanreturns cleaned base64 data and a report.POST /inspect/batchandPOST /clean/batchprocess up to 50 files per request.
The following example base64-encodes a Markdown file and sends it to the cleaning endpoint:
WM="http://127.0.0.1:8765"
curl -s "$WM/health"
curl -s -X POST "$WM/clean" -H 'Content-Type: application/json' \
-d "{\"file\": \"$(base64 < notes.md | tr -d '\n')\", \"name\": \"notes.md\"}"Set WATERMARKS_SERVER_API_KEY to require bearer authentication. If you deploy beyond a local development machine, retain authentication and appropriate network controls.
Run the service with Docker
Build and run the core image with a read-only filesystem and a temporary directory:
make docker-core-build
docker run --rm -p 127.0.0.1:8765:8765 --read-only --tmpfs /tmp watermarks-removerDocker Compose supports several profiles:
docker compose up -d
docker compose --profile harness up -d
docker compose --profile heavy up -d- The default starts the core service.
- The
harnessprofile adds MarkLLM and MarkDiffusion components. - The
heavyprofile adds locally built CtrlRegen and SynthID components.
Core, MarkLLM, and MarkDiffusion images are published on GHCR. CtrlRegen and the SynthID scorer remain local-only because of upstream licensing. Copy .env.example to .env for optional configuration; basic text cleaning requires no additional settings.
Enable automatic checks with a hook
An agent skill is an instruction, so the model decides whether to invoke it. A hook is more deterministic: it runs whenever a matching tool call occurs.
The Claude Code plugin registers a PostToolUse hook for Write, Edit, MultiEdit, and NotebookEdit. It invokes service/scripts/hook_written_file.py in one of two modes:
- check: the default mode reports marks but does not modify the file.
- clean: removes supported marks in place and notifies the model.
Choose the mode through the plugin's Hook mode setting or set:
WATERMARKS_HOOK_MODE=cleanWithout the plugin, you can register the hook manually in ~/.claude/settings.json. Hooks cover files written by the agent and the pre-commit gate, but cleaning text directly in chat transcripts remains best-effort and depends on the skill.
Add a pre-commit check
To stop marked files before they enter a Git commit, add the repository's check hook to .pre-commit-config.yaml:
repos:
- repo: https://github.com/guillaumemeyer/watermarks-remover
rev: v0.5.0
hooks:
- id: watermarks-remover-checkThe watermarks-remover-check hook fails when marks are found. The alternative watermarks-remover-clean hook cleans files in place and is explicitly opt-in.
Advanced tips
Preserve originals and compare results
Write cleaned data to a separate output path whenever possible. This is especially important for Layer B rewrites and complex document containers, where processing may affect prose, embedded assets, or application-specific properties.
Install the right PDF tools
Use qpdf when you need a real structural PDF strip. The README warns that exiftool alone performs an incremental update that can leave old bytes recoverable. Use the optional Ghostscript deep pass when metadata may be present inside embedded images.
Treat detection and cleaning as different operations
A clean operation removes supported carriers and metadata, while a detector estimates whether a configured watermark scheme is present. For example, MarkLLM verification is meaningful only under the same configuration, and keyed-Gumbel replay requires the generation key. These tools are not universal vendor oracles.
Choose Layer B carefully
If you use Layer B, the project recommends a non-origin model to reduce the chance of applying the same kind of mark again. Because heavy paraphrasing can damage tone and precision, skip it when preserving writing quality is the higher priority.
Explore optional backends
Bootstrap scripts under service/scripts/ can configure reverse-SynthID for image scoring, CtrlRegen for pixel-domain removal, MarkLLM for configured text-watermark verification, and MarkDiffusion for image-watermark experiments. These backends have different requirements and limitations; consult their setup scripts before enabling them.
Responsible use
Use watermarks-remover only for privacy, research, and hygiene on content you own or are authorized to process. It is not intended for academic fraud or false claims that AI-generated material was written by a human. Follow applicable laws and institutional policies.
The project is available under the MIT License. For releases and source code, visit the watermarks-remover GitHub repository.
Conclusion
watermarks-remover combines deterministic text cleanup, metadata removal across many file containers, optional detection backends, agent integration, hooks, and an HTTP API. Start with inspection, retain the original, apply the narrowest suitable cleaning layer, and review the result rather than treating any detector outcome as guaranteed.
