Pipeline de Diarios Parlamentarios · ParlaIbero

diaries-*

21 skills nativos de Claude Code que transforman diarios de sesiones parlamentarias —PDF escaneado o digital, HTML, XML, DOCX o texto plano— en matrices estandarizadas de intervenciones. Desde el OCR hasta el esquema canónico final, con un sistema de confianza de tres niveles que mantiene al investigador en control de cada decisión automática.

21 skills nativos
13 en pipeline
8 de control
3 niveles de confianza
16 columnas canónicas

Mapa del pipeline

De la fuente al corpus · 13 skills en secuencia · 8 de control
source/{iso2}/raw/  (PDF / HTML / XML / DOCX / TXT fuente)
        │
        ▼
  /diaries-bootstrap ──► country_config/{iso2}.yaml
        │                state/{iso2}/pipeline_state.json
        │
        ▼
  /diaries-ocr ──────────► source/{iso2}/ocr/{id}/page_NNNN.txt
  (solo si pdf_image)       [LightOnOCR-2:1b → fallback por país: glm-ocr]
        │
        ▼
  /diaries-extract ──────► source/{iso2}/extracted/{id}.txt
  (texto FIEL — NO limpia)      [consolida OCR/PDF/HTML/XML/DOCX/txt · conserva ---PAGE N---]
        │
        ▼
  /diaries-correct ──────► source/{iso2}/corrected/{id}.txt
  (ÚNICO limpiador: 5 pasos)  [mobiliario por país + deshifenización + reflujo]
        │
  /diaries-meta ────────► source/{iso2}/meta/{id}.json
  (fecha, nº, tipo, legislatura, [heurística registrada o DESCUBIERTA]
  presidencia por TRAMOS)    lee extracted/ — la capa fiel, con el cabecero íntegro
        │
        ▼
  /diaries-dedupe ──────► source/{iso2}/_quarantine_duplicates/
  (⚠ ANTES de tag)          [boletín + fecha real · reversible]
  dos clases: (A) misma sesión bajo >1 id · (B) filas dobladas
  por ingesta multi-track · después de tag, su inventario sale sesgado
        │
        ├────────────► /diaries-deputies ──► source/{iso2}/deputies/deputies.csv
        │              (opcional aquí: si hay pase de lista nominal, el padrón
        │               sale de corrected/ y alimenta a tag con --deputies)
        ▼
  /diaries-tag ──────────► source/{iso2}/tagged/{id}.txt
  (⚠ crítico, 0.80/0.60)   [regex 2 niveles → Claude para sospechosos]
  Paso 0c: inventario estructural por FORMA (gate anti-falsos negativos)
        │
        ▼
  /diaries-matrix ────────► source/{iso2}/matrix/interventions_raw.csv
  (parse <int> → CSV)        [gate incrustados ≤0,1% · Prolegomena orden 0]
        │
        ├────────────► /diaries-deputies ──► source/{iso2}/deputies/deputies.csv
        │              (BD de diputados)      [externo o RapidFuzz+Claude]
        ▼
  /diaries-match ─────────► source/{iso2}/match/matching_table.csv
  (⚠ crítico, 0.90/0.70)     [congelado + exact → fuzzy → Claude]
        │
        ▼
  /diaries-merge ─────────► source/{iso2}/merge/interventions_enriched.csv
  (join pandas, period-aware)  [Paso 3-bis: presidencia por TRAMO
  (president_meta) — hasta el 42% del corpus · gate de integridad referencial]
        │
        ▼
  /diaries-standardize ───► source/{iso2}/standardize/{ISO2}_interventions.csv  ⚠ canónico
  (16 columnas canónicas + {ISO2}_deputies.csv)
        │
        ▼
  /diaries-document ──────► docs/{iso2}/README.md
                                      docs/{iso2}/data_dictionary.md
                                      docs/{iso2}/dataset.jsonld

──────────────────────────────────────────────────────────────────
  CONTROL  (disponibles en cualquier momento)

  /diaries-status    → tabla de estado del pipeline
  /diaries-review    → revisar FLAGs y HALTs interactivamente [A/C/E/S/Q]
  /diaries-feedback  → inyectar corrección (punctual/rule/strategy)
  /diaries-decide    → registrar una decisión metodológica CON SU EVIDENCIA
                       state/{iso2}/decisions.jsonl · state/_transversal/
                       docs/_metodologia/generados/METODOLOGIA.md (generado)
  /diaries-report    → informe completo del proceso (lee lo que registró decide)
  /diaries-validate  → validación estructural por muestreo + calibración de fuga
  /diaries-teach     → guía interactiva del sistema
  /diaries-refine    → mejorar un skill a partir de testing real
──────────────────────────────────────────────────────────────────

AUTO · FLAG · HALT

● AUTO
≥ 0.85
umbral por defecto · ajustable por skill

El skill completó la tarea con alta confianza. El pipeline continúa automáticamente al siguiente paso sin ninguna intervención.

Sin acción requerida
◐ FLAG
≥ 0.65
umbral por defecto · ajustable por skill

El resultado es válido pero hay incertidumbre. El pipeline continúa y el caso se registra para revisión posterior en /diaries-review.

Revisar con /diaries-review
✕ HALT
< 0.65
umbral por defecto · ajustable por skill

La confianza es insuficiente para continuar o se produjo un error. El pipeline se detiene y se requiere intervención manual inmediata.

Intervención manual obligatoria
Fórmulas de confianza por skill
/diaries-ocr 0.7 × media_páginas + 0.3 × página_mínima
/diaries-tag  ⚠ 0.80/0.60 n_auto / (n_auto + n_sin_tag + n_llm × (1 − conf_llm))
/diaries-correct integridad: 0.95 si out_chars ≥ 0.80 × in_chars (si no, 0.60 → FLAG)
/diaries-match  ⚠ 0.90/0.70 n_vinculados_auto / n_oradores_únicos
/diaries-meta campos_extraídos / 5
/diaries-standardize 1 − (errores_validación / n_filas)
/diaries-matrix 1 − (bloques_sin_orador / bloques_totales)
/diaries-document 1.0 (determinista, sin LLM)

Pipeline principal · 13 skills

Haz clic en cualquier skill para ver entradas, salidas, fórmula de confianza e invocación.

Entrada
source/{iso2}/raw/*.pdf source/{iso2}/raw/*.html
Salida
country_config/{iso2}.yaml state/{iso2}/pipeline_state.json docs/{iso2}/onboarding_report.md
Confianza
fracción de campos inferidos automáticamente con confianza ≥ 0.80
Invocación
/diaries-bootstrap --country {iso2}

Skill de nivel país: no usa --session ni --batch. Se ejecuta una sola vez por país. Puede reejecutarse con --force para regenerar la configuración.

Entrada
source/{iso2}/raw/{session_id}.pdf
Salida
source/{iso2}/ocr/{session_id}/page_NNNN.txt
Confianza
0.7 × media_confianza_páginas + 0.3 × confianza_página_mínima
Penaliza documentos con una página muy degradada
Parámetros OCR relevantes en country_config
ocr.dpi: 150  ·  ocr.workers: 6  ·  ocr.primary_model  ·  ocr.fallback_model (default: glm-ocr)
Invocación
/diaries-ocr --country {iso2} --all
/diaries-ocr --country {iso2} --session 1931-07-14
/diaries-ocr --country {iso2} --batch 1931-07

Control de la ñ: tras cada lote se miden las variantes rotas de «señor» (seflor, sefior, senor…). Un ratio > 1–2% indica que el primario no preserva la ñ en esa fuente: pasar al fallback y registrar las variantes en ocr.enye_variants para que correct y tag las toleren.

Entrada
source/{iso2}/raw/{id}.pdf  (pdf_digital) source/{iso2}/ocr/{id}/  (pdf_image) source/{iso2}/raw/{id}.{html,xml,docx,txt}
Salida
source/{iso2}/extracted/{session_id}.txt
Confianza
proporción de caracteres Unicode válidos en el texto extraído
Gates que MIDEN, no limpian: fragmentación por ancho de columna (línea mediana < 25 car o > 2% de cortes con guion) y garble del prefijo de orador (> 50% en escaneadas → HALT)
Invocación
/diaries-extract --country {iso2} --all

Capa fiel: extracted/ es el punto de retorno reproducible y no se limpia NUNCA; --strip-headers queda como legado opt-in, fuera del flujo canónico. XML por parser de país: la ruta de CL (parse_cl_xml.py) entra ya etiquetada y vinculada directo a matrix — esas sesiones se saltan extract/correct/tag. Config: extract.emit_page_marker · extract.page_marker_format · extract.page_break_marker.

Entrada
source/{iso2}/extracted/{session_id}.txt
Salida
source/{iso2}/corrected/{session_id}.txt
Limpieza por país · descubrimiento + bucle de residuo
El mobiliario se DESCUBRE por frecuencia y por década (5 clases: block · line · masthead · prefix · inline) y se guarda en country_config. El config inicial NUNCA basta: bucle supervisado descubrir → aplicar → verificar residuo → refinar, con un detector independiente del propio config. Deshifenización en dos variantes (salto Y guion+espacio, 2ª pasada --textdir con léxico del corpus) · join_split_titles opt-in. Gates de salida: ningún marcador partido en corrected/ (si no, marker_join_next y re-correr) · caída de marcadores extracted → corrected > 2% en una sesión = HALT (el acumulador los ENTIERRA — el −N ES la señal). Los Prolegomena JAMÁS se borran.
Confianza
integridad del texto: 0.95 si out_chars ≥ 0.80 × in_chars (y salida no vacía); si no, 0.60 → FLAG
Invocación
/diaries-correct --country {iso2} --all
Entrada
source/{iso2}/extracted/{session_id}.txt (respaldo por sesión: corrected/)
Salida
source/{iso2}/meta/{session_id}.json
Confianza · campos extraídos
campos_extraídos / 5   # fecha · número · tipo · presidente · legislatura
Invocación
/diaries-meta --country {iso2} --all

Sin heurística no se asume formato: se usa la registrada en meta_patterns del config o se DESCUBRE y valida (resolución contra el padrón, contigüidad temporal, cardinalidad, reparto por género). El JSON registra presidency.segments — la lista de tramos, incluido el relevo sin nombre («reasume la Presidencia»). Si date no se resuelve, se deriva al menos el AÑO del session_id (date_year_only + date_source: "session_id_year") — nunca se inventan día y mes.

Entrada
source/{iso2}/{corrected,meta,ocr,raw}/ (lee boletín + masthead)
Salida
source/{iso2}/_quarantine_duplicates/ + manifest.json
Regla de duplicado
Clase A: mismo boletín ∧ misma fecha real   # mismo día con boletín distinto = sesiones legítimas (mañana/tarde) Clase B: desplazamiento constante de orden, o solapamiento ≥ 25% → dedup fila a fila # < 25% = complementaria, NO se toca
Invocación
/diaries-dedupe --country {iso2}            # dry-run
/diaries-dedupe --country {iso2} --write    # cuarentena (reversible, idempotente)

El estado se registra POR SESIÓN: detect_duplicates.py marca complete en cada keeper y skipped en cada redundante — no hay entrada _country. La Clase B siempre informa y pide confirmación explícita; las filas retiradas van a cuarentena reversible con manifiesto, nunca se borran.

Entrada
source/{iso2}/corrected/{session_id}.txt
Salida
source/{iso2}/tagged/{session_id}.txt
Confianza · umbrales reducidos (⚠ 0.80 / 0.60)
n_auto / (n_auto + n_sin_tag + n_llm × (1 − conf_promedio_llm))
Ajuste en country_config
thresholds.diaries-tag.threshold_auto: 0.80 thresholds.diaries-tag.threshold_flag: 0.60 speaker_tag_patterns: [...] # regex de oradores, en orden de prioridad
Las CINCO clases de marcador · semilla por país
FORMAL (la única que abre turno) · APARTE (queda en el texto del anfitrión) · MENCIÓN (se ignora) · VOTO nominal (tag.vote_patterns → dm_speech = 0) · NARRATIVA (tagging_style: narrative — DO/CO: el orador va en una cláusula en prosa). Semilla del descubrimiento: docs/_metodologia/FASE_C_MARCADORES_POR_PAIS.md. Terminadores verificados: ES·GT·EC «:» · UY «.—» · EC también «.-» (grafía OCR) · PT «—» solo. Tolerancia OCR obligatoria: la ñ rota (seflor, sefior, senor…) · EL→FL · H.D.→HE.
⚠ Prerequisito · el corpus debe estar YA deduplicado
/diaries-meta → /diaries-dedupe → /diaries-tag El Paso 0c rankea las formas de marcador por frecuencia sobre TODO el corpus para decidir cuáles entran al léxico. Con sesiones duplicadas dentro, sus formas se cuentan dos veces y la calibración sale sesgada. Deduplicar después NO lo arregla: la decisión ya se tomó sobre datos inflados.
Invocación
# si hay pase de lista, construye antes el padrón y pásalo:
/diaries-deputies --country {iso2}

/diaries-tag --country {iso2} --all
/diaries-tag --country {iso2} --session 1931-07-14 --dry-run

⚠ Gate anti-falsos-negativos (verify_tagging.py): una sesión con n_residual_markers ≥ 1 va a HALT — ABSOLUTE FAIL, nunca a complete ni a flag. diaries-matrix aborta mientras exista una sola sesión así: un marcador sin etiquetar atribuye su intervención entera al orador anterior, en silencio.

Entrada
source/{iso2}/tagged/{session_id}.txt source/{iso2}/meta/{session_id}.json
Salida
source/{iso2}/matrix/interventions_raw.csv
Confianza
1 − (bloques_sin_orador / bloques_totales) # penalizada si la cobertura de tags < 80%
Gates de la matriz
Entrada: ABORTA si alguna sesión de diaries-tag está en HALT por falsos negativos. Incrustados (marcador absorbido en el text de otra fila): ratio ≤ 0,1% → aceptable, split_embedded_markers.py divide el residuo; > 0,1% → NO se parchea el CSV: se corrige la capa de origen y se re-corre correct → tag → matrix. Prolegomena: todo lo anterior al primer marcador entra como fila con intervention_order = 0 y dm_speech = 0, sin desplazar la numeración (recover_frontmatter.py). Sin tope de longitud. ANEXOS del diario: dm_speech = 0 SOLO donde el acta marca separador explícito (matrix.annex_separator); sin marca no se especula. Default: dm_speech = 1 — el 0 solo donde está demostrado.
Invocación
/diaries-matrix --country {iso2} --all
Entrada
source/{iso2}/matrix/interventions_raw.csv o fichero externo (deputies.external_file)
Salida
source/{iso2}/deputies/deputies.csv source/{iso2}/standardize/{ISO2}_deputies.csv (publicable)
Confianza
1 − (n_diputados_ambiguos / n_diputados_total)
Precedencia de fuentes · sex derivada
manual > camara:oficial > acta:bloque > registro (jce:) > web > *:inferido > (vacío) sex es variable DERIVADA: cascada con procedencia declarada en sex_source (manual · official_registry · roster · honorific …). El padrón publicable standardize/{ISO2}_deputies.csv acompaña a la matriz y se une por id_dep + legislature (una fila por persona EN una legislatura).
Invocación
/diaries-deputies --country {iso2}
Entrada
source/{iso2}/matrix/interventions_raw.csv source/{iso2}/deputies.csv
Salida
source/{iso2}/match/matching_table.csv
Confianza · umbrales elevados (⚠ 0.90 / 0.70)
n_vinculados_automáticamente / n_oradores_únicos
Estrategia: exacto → token_sort_ratio ≥ umbral_fuzzy → LLM → unmatched
Reglas que mandan sobre el fuzzy
CONGELADO: 106.938 decisiones speaker_raw → id_dep en 13 países (frozen_matching.py). Se comprueban al inicio (--check) y se RE-IMPONEN al FINAL (--apply, Paso 6-final): un reproceso no puede revertirlas. Lo que ya no casa se INFORMA en docs/{iso2}/vinculacion_huerfana.csv — nunca se borra. VENTANA de sesión (match_ventana.py): umbral calibrado POR PAÍS, no transferible. GÉNERO del cargo: solo la forma FEMENINA (LA PRESIDENTA) autoriza a vincular por sexo; la masculina es genérica, y una forma de cargo nunca se vincula en bloque. PRIMACÍA del diario: una intervención NUNCA se elimina porque su orador no case.
Invocación
/diaries-match --country {iso2}
/diaries-match --country {iso2} --force   # re-ejecutar todo
Entrada
interventions_raw.csv matching_table.csv deputies.csv
Salida
source/{iso2}/merge/interventions_enriched.csv
Confianza
n_filas_con_id_dep / n_filas_totales # recalculada sobre el enriched FINAL, tras 3-bis
Paso 3-bis · Atribución de la presidencia por TRAMO (president_meta)
Muchas cámaras etiquetan a quien preside solo con el cargo (PRESIDENTE, PRESIDENTA, O SR. PRESIDENTE), sin nombre. Sin este paso esas filas se quedan sin id_dep para siempre: PE 42,1% · DO 36,5% del corpus. Se ejecuta con attribute_presidency.py (--apply / --check), parametrizado en country_config (presidency: scope session|segments · sources · target_exclude · back_to_base) — NO se escribe un script por país. El modo por tramos sigue los relevos que el propio acta declara (meta los registra en presidency.segments): un solo presidente por sesión falla el 35,0% de los casos (UY, medido). Marca match_method = "president_meta" para que el origen quede auditable. ⚠ REGLA DE PARADA — no inventes cuando hay varias presidencias: 1 sola presidencia .................. atribuye varias, distinto sexo ............... desempata con PRESIDENTE/PRESIDENTA contra el sexo del padrón conviven titular y «en funciones», o 2+ del mismo sexo ................. NO atribuyas — el acta nombra a quienes presidieron, pero no dice cuándo se produjo el relevo
Paso 3d · Consistencia temporal (obligatoria)
fecha_inicio ≤ date ≤ fecha_fin para toda fila con id_dep referencias: DO 99,96% · PE 97,40% < 99% → FLAG
Paso 3-ter · Integridad referencial matriz ↔ padrón (Gate E)
Todo id_dep del enriched debe existir en deputies.csv, y todo par (id_dep, legislatura) debe existir en el padrón. Se comprueba ANTES de standardize. id_dep inexistente → error duro: se corrige, no pasa al canónico. Par huérfano → la fila NUNCA se elimina (primacía del diario): se completa el padrón o se declara en process_report.md como medida de completitud.
Invocación
/diaries-merge --country {iso2}
Entrada
source/{iso2}/merge/interventions_enriched.csv
Salida ⚠ canónica · la entrega son DOS archivos
source/{iso2}/standardize/{ISO2}_interventions.csv source/{iso2}/standardize/{ISO2}_deputies.csv (padrón, join por id_dep)
Columnas canónicas — 16 (en orden)
id_session · id_int · legislature · legislative_session · session_number · date session_type · intervention_order · speaker_raw · id_dep · speaker_name · sex party · district · dm_speech · text id_session/id_int los asigna asignar_ids.py · dm_speech binaria (el 0 solo donde está demostrado) · Prolegomena = intervention_order 0 · separador «;» SOLO ES y GT
Paso 4-bis · legislature  ·  Paso 4-ter · ids en TRES sub-pasos
4-bis: legislature se normaliza al PERÍODO CONSTITUCIONAL — comprobar la cardinalidad (en DO la fuente daba 145 valores para 7 legislaturas reales). 4-ter, en orden fijo: a) desdoblar Prolegomena duplicados (desdoblar_prolegomena_duplicado.py: copias exactas fuera, las distintas se sufijan 104 → 104B) b) asignar_ids.py — {ISO2}{leg:03d}{ses:04d}{orden:05d}; se niega si hay colisión c) verificar VALORES: id_int no vacío y único (rc=0 no basta — buscar «✗»)
Confianza
1 − (errores_validación_pydantic / n_filas)
⚠ Seguridad de reejecución · qué destruye un --force
El guardia protege el archivo, pero NO avisa de lo que se pierde. Sobre un corpus ya cerrado suele haber operaciones POSTERIORES al pipeline estándar: 1 · sidecar LEGADO → sus filas se reintegran con dm_speech=0; nada se vuelve a apartar 2 · atribuciones post-merge → viven solo en el enriched, no en (match_method = president_meta) la matching_table 3 · correcciones humanas → manual / NOT_SPEAKER / role Compara SIEMPRE el recuento antes y después. Si al regenerar bajan las filas vinculadas, has perdido trabajo: recupéralo del backup antes de continuar.
Invocación
/diaries-standardize --country {iso2}
/diaries-standardize --country {iso2} --force   # sobreescribir canónico

⚠ Se niega a sobreescribir {ISO2}_interventions.csv sin --force. El archivo canónico es irrecuperable si se sobreescribe por accidente.

Entrada
country_config/{iso2}.yaml state/{iso2}/pipeline_state.json source/{iso2}/standardize/{ISO2}_interventions.csv source/{iso2}/standardize/{ISO2}_deputies.csv match/matching_table.csv (vinculación efectiva)
Salida
docs/{iso2}/README.md docs/{iso2}/data_dictionary.md docs/{iso2}/dataset.jsonld docs/{iso2}/corpus_info.json
Invocación
/diaries-document --country {iso2}

Dos tasas, dos archivos: el README enuncia la vinculación bruta (filas con id_dep / total) Y la efectiva (excluido el denominador no vinculable: mesa sin persona, NOT_SPEAKER, no-discurso). dataset.jsonld declara los DOS archivos de la distribución: {ISO2}_interventions.csv + {ISO2}_deputies.csv (unible por id_dep + legislature). La documentación se regenera SIEMPRE entera y por una sola puerta.

Comandos de control

/diaries-status

Muestra el estado del pipeline en tabla: los 13 skills en su orden canónico (bootstrap → ocr → extract → correct → meta → dedupe → tag → matrix → deputies → match → merge → standardize → document) × niveles (completo / flag / halt / pendiente). dedupe se cuenta POR SESIÓN.

/diaries-status --country {iso2}
/diaries-review

Revisión interactiva de casos FLAG y HALT. Para cada FLAG: evidencia, confianza y decisión [A]ceptar · [C]orregir · [E]scalar · [S]altar. Los HALT se listan con su error y se marcan resueltos tras la intervención manual.

/diaries-review --country {iso2}
/diaries-feedback

Inyecta una corrección en el estado. Tres tipos: punctual (1 sesión), rule (desde fecha → re-procesa), strategy (todo el skill + --force).

/diaries-feedback --country {iso2} --skill diaries-tag \
  --type rule \
  --description "Nuevo patrón de orador" \
  --pattern "^EL SR\." --action "tag_as_speaker" \
  --from 1931-09-01
/diaries-report

Genera el informe interno del proceso: línea temporal, distribuciones de confianza, historial de correcciones y tasa de automatización. Escribe pipeline_report.md, nunca process_report.md: ese es el informe público que produce la cadena del depósito (decisión ar-0029).

/diaries-report --country {iso2}
# Salida: docs/{iso2}/pipeline_report.md
/diaries-decide

Registra una decisión metodológica en el momento, con su evidencia. Capturar e informar son cosas distintas: lo que no se captura cuando se decide, se pierde. La evidencia es obligatoria y se valida — existe para impedir que se registre una preferencia como si fuera un hallazgo. Las decisiones superadas no se borran: se marcan y se enlazan desde la que las anula, y esa cadena es el historial de correcciones del corpus.

/diaries-decide   # modo interactivo

# consultar lo registrado
python3 ~/.claude/skills/diaries-lib/lib/utils/record_decision.py \
  --pais {iso2} --listar

# regenerar el documento metodológico
python3 scripts/generar_metodologia.py
# Salida: docs/_metodologia/generados/METODOLOGIA.md
/diaries-validate

Valida la integridad estructural del corpus por muestreo, con auto-filtro PASS/FLAG y calibración empírica de la tasa de fuga. Produce la cifra de calidad que el corpus puede afirmar, no la que se supone.

/diaries-validate --country {iso2}
/diaries-teach

Guía interactiva del sistema. Ofrece 8 caminos: visión general, nuevo país, retomar pipeline, problemas por skill, sistema AUTO/FLAG/HALT, correcciones, mapa completo y registro de decisiones metodológicas.

/diaries-teach
/diaries-refine

Mejora un skill a partir de una observación de testing real. Edita directamente el SKILL.md en ~/.claude/skills/, donde el cambio queda activo de inmediato, y lo registra en REFINEMENTS.md.

/diaries-refine --skill diaries-tag \
  --issue "Los patrones multi-línea no se detectan"

/diaries-refine   # modo interactivo

Flujos de trabajo

Nuevo país desde cero

Para un código ISO2 que no existe aún en el sistema.

1
Colocar los archivos fuente
source/{iso2}/raw/YYYY-MM-DD.pdf
2
Configurar el país
/diaries-bootstrap --country {iso2}
3
Cadena de ingesta
/diaries-ocr --country {iso2} --all /diaries-extract --country {iso2} --all /diaries-correct --country {iso2} --all /diaries-review --country {iso2} # meta y dedupe ANTES de tag /diaries-meta --country {iso2} --all /diaries-dedupe --country {iso2} # opcional: si hay pase de lista nominal /diaries-deputies --country {iso2} /diaries-tag --country {iso2} --all /diaries-review --country {iso2} /diaries-matrix --country {iso2} --all
4
Resolución de entidades
/diaries-deputies --country {iso2} /diaries-match --country {iso2} /diaries-review --country {iso2}
5
Finalización
/diaries-merge --country {iso2} /diaries-standardize --country {iso2} /diaries-document --country {iso2} /diaries-report --country {iso2}
Retomar pipeline interrumpido

Cuando el proceso se detuvo por FLAGS sin resolver o un error HALT.

1
Diagnosticar el estado
/diaries-status --country {iso2}
2
Resolver FLAGs pendientes
/diaries-review --country {iso2}
3
Si hay un error sistemático, inyectar regla
/diaries-feedback --country {iso2} \ --skill diaries-tag \ --type rule \ --description "descripción del patrón" \ --from YYYY-MM-DD
4
Continuar desde el skill detenido
/{skill_detenido} --country {iso2} --all
Tip
Si no sabes por dónde empezar, /diaries-teach ofrece diagnóstico interactivo guiado paso a paso.

Instalación

1 Instalar los skills

Los 21 skills y su biblioteca (diaries-lib) se publican en el repositorio parlaibero-tools. install_skills.sh los copia a ~/.claude/skills/, la ruta desde la que los llama Claude Code. Si ya tienes alguno, se detiene sin tocarlo; --force los sustituye y guarda antes una copia.

git clone https://github.com/rodrodr/parlaibero-tools.git
cd parlaibero-tools
bash install_skills.sh
2 Preparar el proyecto

En la carpeta que vaya a contener los datos, un único script instala las dependencias Python, verifica que los 21 skills estén en ~/.claude/skills/ y crea la estructura de directorios.

mkdir mi-corpus && cd mi-corpus
bash ~/.claude/skills/diaries-lib/install.sh
3 Empezar

Copia las fuentes en source/{iso2}/raw/, abre Claude Code desde la carpeta del proyecto y ejecuta la guía interactiva, o configura directamente el país.

/diaries-teach
/diaries-bootstrap --country {iso2}

Skills · dónde viven

Claude Code usa los 21 SKILL.md de ~/.claude/skills/diaries-*/, y es esa copia la que se edita — p.ej. con /diaries-refine, cuyo cambio queda activo de inmediato y se registra en REFINEMENTS.md. La carpeta skills/ del repositorio es la versión publicada: para pasar a una más nueva, git pull y bash install_skills.sh --force, que guarda antes una copia de la instalada (también de lo que hayas cambiado en ella).

Ollama · OCR local

Necesario solo para PDFs escaneados (pdf_image). El instalador avisa si falta.

ollama pull Maternion/LightOnOCR-2:1b  # primario
ollama pull glm-ocr                    # fallback por defecto (por país)
Estructura de directorios generada automáticamente

Al ejecutar /diaries-bootstrap por primera vez para un país, se crean todos los subdirectorios necesarios:

source/{iso2}/
├── raw/                  ← fuentes originales (tú las colocas)
├── ocr/{session_id}/     ← páginas OCR por sesión
├── extracted/            ← texto FIEL (conserva ---PAGE N---)
├── corrected/            ← párrafos corregidos
├── tagged/               ← texto con <int> tags
├── meta/                 ← JSON de metadatos
├── matrix/               ← interventions_raw.csv (acumulativo)
├── deputies/             ← deputies.csv
├── match/                ← matching_table.csv
├── merge/                ← interventions_enriched.csv
└── standardize/          ← {ISO2}_interventions.csv (canónico ⚠)
                            + {ISO2}_deputies.csv (padrón publicable)

docs/{iso2}/
├── README.md          ← documentación principal del corpus
├── data_dictionary.md ← diccionario de variables
├── dataset.jsonld     ← metadatos Schema.org (CC BY 4.0)
├── corpus_info.json   ← respuestas del procesador (reutilizable)
└── pipeline_report.md ← informe interno del proceso (/diaries-report)

El directorio docs/{iso2}/ es independiente de source/{iso2}/: la documentación de cada corpus nacional es un activo propio, separado de los datos de trabajo.

Lo que hace install.sh

✓ Verifica Python 3.11+
✓ Instala las 8 dependencias vía pip
✓ Verifica los 21 skills en ~/.claude/skills/ (no los copia: eso lo hace install_skills.sh)
✓ Crea state/, source/, country_config/, docs/
✓ Verifica Ollama y modelos OCR disponibles
✓ Es idempotente: re-ejecútalo cuando quieras (no toca los skills)