
Una aplicación que prioriza la privacidad y elimina las marcas de agua de IA del contenido que te pertenece.
_ _ _ ____ ___ ____ ____ _ _ ____ ____ _ _ ____ ____ ____ _ _ ____ _ _ ____ ____
| | | |__| | |___ |__/ |\/| |__| |__/ |_/ [__ __ |__/ |___ |\/| | | | | |___ |__/
|_|_| | | | |___ | \ | | | | | \ | \_ ___] | \ |___ | | |__| \/ |___ | \
Habilidad de agente + servicio Python de biblioteca estándar para eliminar marcas de procedencia de IA de múltiples proveedores de texto y archivos — para privacidad e higiene en contenido que te pertenece. La habilidad es un cliente ligero: controla la maquinaria a través de HTTP, por lo que el host del agente no necesita Python.
| Capa | Objetivo | Cómo |
|---|---|---|
| A | Unicode invisible, espacios exóticos, bidi, caracteres de etiqueta | Scripts deterministas de Python |
| B | Marcas de agua estadísticas (muestreo de tokens) en texto | Reescritura del agente + hook opcional rewrite_text.py |
| Archivos | C2PA / EXIF / XMP / propiedades de documentos | PNG, JPEG, WebP, AVIF, HEIC, BMP, GIF, TIFF, SVG, PDF, DOCX, XLSX, PPTX, EPUB, ODT, HTML, Markdown, MP4/MOV/M4A/M4V, WAV, MP3, FLAC |
Proveedores / ecosistemas (a nivel de clase): Claude, Gemini / SynthID-Text, superficies de procedencia de OpenAI, marcas open-LLM estilo Kirchenbauer (lista verde) y Gumbel con clave / EXP (Aaronson).
Última versión: v0.7.0
Ruta de la habilidad: skills/remove-ai-marks/
Ruta del servicio: service/
(migración: anteriormente remove-claude-marks; el alias de barra /remove-claude-marks sigue documentado)
La habilidad no incluye código — llama al servicio a través de HTTP. Instala la habilidad (solo markdown) e inicia el servicio, luego configura WATERMARKS_SERVICE_URL si no es http://127.0.0.1:8765.
En Claude Code, la ruta más rápida es el marketplace de plugins incluido — sin clonar, y se actualiza en el lugar. En cualquier otro lugar, un instalador cubre todos los hosts compatibles (Python 3.10+ biblioteca estándar, sin dependencias):```bash python3 install_skill.py --skill remove-ai-marks --target claude-code
| Host | Target | Lands in |
| --- | --- | --- |
| Claude Code (personal) | `--target claude-code` | `~/.claude/skills/<skill>` (honors `CLAUDE_CONFIG_DIR`) |
| Claude Code (project) | `--target claude-project --project-dir PATH` | `PATH/.claude/skills/<skill>` |
| Cowork, claude.ai, cloud sessions, routines | `--target cowork` | `dist/<skill>.zip` to upload under **Customize → Skills** |
| Cursor | `--target cursor` (default) | `~/.cursor/skills/<skill>` |
Shipped skills: `remove-ai-marks` (full, service-backed) and
`clean-user-facing-text` (text only, self-contained). `--list` prints them.
Existing installations are preserved unless you pass `--force`; replacement is
staged first and the previous install is kept as a uniquely named backup.
`--link` symlinks this checkout instead of copying, so edits are picked up
live. On Windows, use `py install_skill.py ...`; the `install-skill.sh` wrapper
is provided for macOS/Linux shells.
Before writing anything, the installer validates the skill against the
[Agent Skills](https://agentskills.io) packaging rules that claude.ai uploads
and the Skills API enforce: spec-only frontmatter (`name`, `description`,
`license`, `compatibility`, `metadata`, `allowed-tools`), a lowercase hyphenated
`name` of at most 64 characters matching the directory, a non-empty
`description` of at most 1024 characters. The Cowork bundle additionally has
to fit the 30 MB upload limit, which the packager enforces.
### Limpieza automática mediante hook (determinista)
Una skill es una instrucción: el modelo decide si invocarla, y el
modelo es lo que produce las marcas. Un **hook** es ejecutado por el harness
en cada llamada a herramienta que coincida, sin necesidad de cooperación. Eso hace del hook la
mitad determinista de este flujo de trabajo.
El plugin registra un hook `PostToolUse` sobre `Write|Edit|MultiEdit|NotebookEdit`
que ejecuta [`service/scripts/hook_written_file.py`](https://github.com/guillaumemeyer/watermarks-remover/blob/main/service/scripts/hook_written_file.py)
contra el archivo que el agente acaba de escribir. Dos modos, que coinciden con la convención de pre-commit de comprobar por defecto:
| Modo | Comportamiento |
| --- | --- |
| `check` (default) | Reporta las marcas de procedencia, deja el archivo intacto. Los hallazgos van al modelo (exit 2), para que pueda ofrecerse a limpiarlos. |
| `clean` | Elimina las marcas in situ, luego informa al modelo que el archivo en disco cambió. |
Establece el modo desde la configuración del plugin (**Hook mode** en `/plugin manage`,
leído por el hook como `CLAUDE_PLUGIN_OPTION_HOOK_MODE`), o con
`WATERMARKS_HOOK_MODE=clean` en el entorno. El comando del hook deliberadamente
**no** interpola `${user_config.hook_mode}`: Claude Code se niega a ejecutar
un hook que hace referencia a una opción que el usuario nunca ha abierto en `/plugin manage` para
establecer — un `default` declarado no lo satisface — así que interpolarlo significaría
que el hook silenciosamente nunca se ejecutaría en una instalación nueva. La detección reutiliza `scan_file` / `is_actionable` de `audit_lib`,
así que el hook, la puerta de pre-commit y la exportación SARIF de CI coinciden en qué cuenta como accionable; la limpieza invoca a
`clean_file.py`, así que no se duplica lógica de limpieza. El modo `clean` escribe en un
archivo temporal hermano y solo lo intercambia ante una diferencia real, así que los archivos que ya
estaban limpios conservan su mtime y no vuelven a activar los observadores de archivos.
Sin el plugin, conéctalo tú mismo en `~/.claude/settings.json` (o en un
`.claude/settings.json` de proyecto):```json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit|NotebookEdit",
"hooks": [
{
"type": "command",
"command": "python3",
"args": ["/path/to/watermarks-remover/service/scripts/hook_written_file.py",
"--mode", "check"],
"timeout": 30
}
]
}
]
}
}
En Windows, reemplaza python3 por py.
Lo que un hook no puede hacer. Ningún hook puede reescribir el mensaje de chat del asistente
antes de que lo leas. El hook Stop de Claude Code recibe last_assistant_message
como solo lectura, y no existe un filtro previo al envío para las respuestas finales — el mismo límite
que este proyecto ya documenta para las reglas de Cursor. Por lo tanto, la garantía
determinista cubre los archivos que el agente escribe, más la
puerta de pre-commit para cualquier cosa que esté en camino a git. El texto que
solo existe en la transcripción del chat todavía depende del flujo de trabajo de la skill,
que está basado en instrucciones del modelo y por lo tanto es de mejor esfuerzo.