¿Qué hace org-lint?
Linter para las reglas de formato de prosa en archivos org/md, documentadas en
~/.claude/rules/org-babel.md. El objetivo no es
depender cada vez de la memoria manual sobre cada regla (y con ello el riesgo de corregir la
recién mencionada y pasar por alto el resto), sino pasar el texto por una lista explícita.
Cuándo aplicarlo
- Inmediatamente después de editar o escribir un nuevo párrafo de prosa en un archivo
.org/.md(en lugar de verificar manualmente cada regla de memoria) — antes de mostrar el resultado al usuario. - Ante una solicitud explícita del usuario ("revisa las reglas org", "ejecuta el linter", comparación con
clippy, etc.). - No se aplica al contenido de bloques
#+begin_src/#+begin_example(código) — solo a párrafos de prosa y encabezados.
Paso 1 — verificación mecánica
Ejecuta el script sobre el(los) archivo(s) editado(s):
python3 ~/.claude/skills/org-lint/scripts/lint.py RUTA/AL/ARCHIVO.org
El script detecta mediante regex:
/sin espacios alrededor de~...~/=...=(~a~/~b~en lugar de~a~ / ~b~) — INFRACCIÓN SEGURA.[[file:../— enlace relativo al directorio actual en lugar de la abreviaturaroot:— INFRACCIÓN SEGURA.- falta de nueva línea final en el archivo — INFRACCIÓN SEGURA.
- acrónimo en mayúsculas dentro de
=...=(ej.=CSS=) — requiere confirmación (excepciones raras permitidas). - cursiva
/Palabra/— requiere verificación: ¿es realmente un término del glosario del proyecto (existe una sección enspcfctn/glossary.org? ¿hay un enlace a él en la primera mención en este archivo?), o es un enlace a una sección/archivo NO convertido por error (debería ser[[*Sección][...]]). - mención de archivo como
=ruta/archivo.org=— requiere verificación: ¿no debería ser un enlace real[[file:...]]? - palabra "parámetro"/"parámetros"/... — requiere verificación: si se refiere a propiedades de un componente Rust/Yew
(
struct ...Props), la traducción correcta es "propiedades"/"propiedad", no "parámetros"/"parámetro" (término obsoleto). Fuera de componentes Yew (parámetros de función, CLI, procedimientos REST, etc.) "parámetro" es correcto, no lo modifiques. - el bloque
:noweb-ref Definiciónaparece en una sección antes que el bloque:noweb-ref Declaraciones— requiere verificación: la declaración debe ir primero, en orden de lectura del archivo de arriba a abajo (ver org-babel.md). - varios bloques
#+begin_srccon la MISMA:tangle RUTAy sin:noweb yes/<<...>>en el archivo — INFRACCIÓN SEGURA (concatenación obsoleta, como en el antiguogitignore.org— ver org-babel.md). Rehacer como un solo bloque contenedor:tangle+:noweb yescon uno(s) placeholder(s)<<Nombre>>y secciones con:noweb-ref Nombre. - el archivo se tanglea a VARIOS archivos destino diferentes, de los cuales AL MENOS DOS consumen noweb
(tienen
:noweb yesen un#+begin_srcesqueleto, ej.config.org→.env.example+parameters.php), pero al menos un bloque:noweb-ref/<<...>>se nombra sin prefijo de destino (Nombreen lugar deenv:Nombre) — INFRACCIÓN SEGURA (ver org-babel.md, regla sobre prefijos en archivos org multi-destino). Para archivos con UN SOLO archivo destino, así como para archivos donde solo UN destino consume noweb y el resto son destinos:tangleautocontenidos de un solo bloque sin<<...>>(ej.gitignore.org: 5 destinos:tangle, pero solo el.gitignoreraíz mediante esqueleto noweb) — no se necesita prefijo, pues no hay ambigüedad real. - los parámetros en el encabezado
#+begin_srcestán en orden incorrecto — INFRACCIÓN SEGURA. El orden correcto es: tipo de bloque →:noweb yes→:noweb-sep "..."→ resto de parámetros →:tangle RUTAo:noweb-ref Nombre(al final, ver org-babel.md). - el archivo se llama
cargo.org— INFRACCIÓN SEGURA (nombre obsoleto para proyectos Rust; renómbralo aconfig.org, ver org-babel.md). :tangleusa ruta absoluta (/...,~/...) o ascendente..— INFRACCIÓN SEGURA (ver org-babel.md); el destino debe ser una ruta relativa descendente desde el archivo org. Si el destino está fuera del árbol fuente, se necesita un symlink u otra estructura de directorios, no../ruta absoluta (episodio:farba-override→farba-thememediante../farba-theme/..., tareaFS-1085).- mayúsculas fuera de
=...=(ej.NO,SOLO) — requiere verificación: si es para resaltar una palabra, y no un acrónimo/abreviatura, reemplázalas por negrita org (*no*), no mayúsculas. - palabra "hook"/"gancho" (traducción de "hook", React/Yew) — obsoleta; la traducción correcta es "enganche"
(aplica solo a prosa, no a identificadores de código como
use_effect_with). - líneas de prosa de más de 105 caracteres — requiere
fill-paragraphmedianteemacsclient(ver abajo).
Los hallazgos "SEGUROS" siempre deben corregirse. Los que "requieren verificación manual" — revísalos uno por uno, pero no todos son
errores (ej. =rest=/=forge-yew= son abreviaturas/nombres de crate legítimos, no infracciones).
Paso 2 — lista de verificación manual (lo que el script no detecta)
- Identificadores/tipos/funciones/variables/módulos de código — y cualquier fragmento o expresión de código (ej.
id=1,value == 0,items()) — tilde~...~. Abreviaturas/acrónimos y la forma "pública" del nombre del crate/biblioteca (con guion) — signo igual=...=. Una ruta calificadacrate::Tipoes un nombre de tipo de código, por lo tanto completamente entre tildes, incluso con prefijo de crate. - Abreviaturas/acrónimos — en minúsculas dentro de una oración, solo la primera letra mayúscula al inicio de una oración (sin mayúsculas completas), salvo excepciones establecidas raras.
- Enlace a una sección en el mismo archivo —
[[*Nombre del encabezado][Nombre]], no cursiva ni solo texto. Enlace a un archivo en el mismo directorio — simplemente[[file:vecino.org][descripción]]; a un archivo en otro directorio (más aún en otro repositorio git dentro del directorio de trabajo común) — mediante la abreviaturaroot:([[root:code/ads-back/archivo.org::N][descripción]]), no../../../relativo al directorio actual. La abreviatura se declara en.dir-locals.elen la raíz del directorio de trabajo (formaevalconlocate-dominating-file) — si aún no existe en el proyecto, créala. - Cursiva
/.../— solo para términos del glosario del proyecto (con traducción(/translation/)inmediatamente después); en la primera mención del término en cada archivo —[[file:.../spcfctn/glossary.org::*Término][...]]a la sección correspondiente, no repitiendo la definición.
Paso 3 — reflujo
Para cada párrafo editado, invoca el fill-paragraph real mediante emacsclient --eval, no
lo refluyas manualmente (ver la regla correspondiente en org-babel.md). Escribe el texto del párrafo en new_string/al crear
el archivo en una sola línea, sin intentar adivinar los saltos de línea tú mismo — de todos modos, eso lo determina por completo fill-paragraph.
Es obligatorio invocar (font-lock-ensure) ANTES de org-fill-paragraph: un búfer abierto headless mediante
find-file-noselect no pasa por fontificación, por lo tanto los enlaces org [[ruta][descripción]] aún no están "plegados" a
texto visible corto descripción — sin font-lock-ensure, fill-paragraph calculará el salto de línea sobre el
texto largo sin procesar del enlace, no sobre su ancho visible, y el resultado diferirá de lo que da M-q en un
Emacs interactivo en vivo. Ejemplo:
emacsclient --eval '
(let ((buf (find-file-noselect "RUTA/AL/ARCHIVO.org")))
(with-current-buffer buf
(org-mode)
(font-lock-ensure)
(goto-char (point-min))
(search-forward "fragmento único del párrafo")
(org-fill-paragraph)
(save-buffer)))
'