CommunityRedacción y edicióngithub.com

lukethecat/aperture

Una habilidad para agentes de IA que seleccionan mejores informes diarios: escanea portadas, registra cada decisión y aprende de la retroalimentación.

¿Qué es aperture?

Aperture es una habilidad de curación de noticias determinista y auditable para agentes de IA, diseñada para reemplazar los lectores RSS estáticos y los resumidores de LLM de un solo uso. Permite a los agentes escanear portadas de fuentes, difuminar contra la instantánea del día anterior, preseleccionar artículos utilizando un perfil de preferencias ponderado, revisar con un LLM, deduplicar y publicar un informe diario, todo mientras registra cada decisión en un diario de solo añadir. La habilidad admite múltiples tipos de fuentes (pull, scan, push, search, human-feed) y proporciona un bucle de reflexión que actualiza el perfil del agente basado en la retroalimentación del usuario, manteniendo versionado todo cambio. Su implementación de referencia en Python es opcional; el agente puede ejecutarlo leyendo este archivo SKILL.md o portando los patrones a su propio entorno de ejecución. Es especialmente útil para desarrolladores que construyen asistentes de investigación o agentes de inteligencia de mercado que necesitan informes consistentes, auditables y que mejoren con el tiempo.

Compatible con~Claude Code✓Codex CLI~Cursor
npx skills add lukethecat/aperture

Installed? Explore more Redacción y edición skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Habilidad: Aperture

Resumen — Una habilidad para agentes de IA que quieren producir mejores informes diarios y descubrir más de lo que sus usuarios realmente desean. Aperture escanea las portadas de las fuentes, las difumina contra las de ayer, preselecciona con un perfil ponderado, revisa con un LLM, deduplica, publica y evoluciona el perfil a partir de la retroalimentación del usuario. Todas las decisiones se registran en un diario de solo añadir.

Esta habilidad es independiente de la implementación. Un agente puede ejecutarla leyendo este archivo, llamando a la implementación de referencia en Python incluida, o portando los patrones a su propio entorno de ejecución.


1. Propósito

Dotar a los agentes de una habilidad de curación de noticias determinista y auditable que reemplaza los lectores RSS estáticos y los resumidores de LLM de un solo uso:

  1. Escanea la portada — trata "leer la portada" como una operación de primera clase, no solo como sondeo de feeds.
  2. Registra cada decisión — registra cada instantánea de fuente, elemento, motivo de rechazo, versión del perfil e informe en un registro de solo añadir para auditoría y reproducción.
  3. Aprende de la retroalimentación — actualiza el gusto del agente a través de comentarios explícitos y mantiene cada cambio versionado y reversible.

Cuando un agente ejecuta esta habilidad, puede responder "¿por qué se seleccionó esto?" y "¿qué habría sido diferente ayer?" a partir del registro.


2. Conceptos centrales

ConceptoSignificado
VerticalUna categoría de noticias configurada (por ejemplo, tecnología, automoción, política de IA). Cada vertical tiene sus propias fuentes, perfil y registro.
RegistroArchivo JSONL de solo añadir. Un archivo por vertical. Cada instantánea de fuente, elemento, versión del perfil, retroalimentación e informe es un registro.
PerfilEl "gusto" del vertical: palabras clave ponderadas, categorías con bonificaciones y términos negativos. Versionado; cada cambio se registra.
EscaneoObtiene la página de listado de cada fuente, extrae títulos/enlaces, normaliza URLs, difumina contra la instantánea anterior.
Bucle de reflexiónRetroalimentación del usuario → operaciones de perfil analizadas → aumento de versión → registro de evolución → re-verificación de elementos recientemente agrupados.

3. Proceso de cuatro etapas

┌─────────┐    ┌──────────┐    ┌─────────┐    ┌──────────┐
│ recolectar│ -> │   editar  │ -> │ revisar  │ -> │ publicar │
│ (escaneo)│    │(preselec.│    │  (LLM)  │    │ (dedup + │
│         │    │  reglas)  │    │         │    │  informe)│
└─────────┘    └──────────┘    └─────────┘    └──────────┘
     │               │               │               │
     └───────────────┴───────────────┴───────────────┘
                         │
                   REGISTRO de solo añadir

3.1 Recolectar — escanear la portada

Objetivo: producir los elementos candidatos de hoy de cada fuente configurada.

Pasos:

  1. Para cada fuente, obtener list_url.
  2. Extraer pares {title, url} usando el extract_profile de la fuente:
    • rss — analizar bloques <item>.
    • generic_links — analizar etiquetas <a href>.
    • regex — aplicar una expresión regular con grupos nombrados para título/url/fecha.
    • json_api — navegar por una ruta JSON y leer claves de título/url.
  3. Normalizar cada URL:
    • Eliminar fragmentos y parámetros de rastreo (utm_*, fbclid, etc.).
    • Eliminar la barra inclinada final y el www. inicial.
    • Forzar esquema https, minúsculas en el host.
  4. Difuminar contra la instantánea de portada anterior para esta fuente (leída del registro).
    • Los nuevos valores url_norm se convierten en candidatos.
    • Guardar la instantánea completa actual como un nuevo registro frontpage en el registro.
  5. Actualizar la salud de la fuente:
    • Éxito → restablecer fail_count.
    • Fracaso → incrementar fail_count; alertar si hay ≥ 3 fallos consecutivos.

¿Por qué difuminar contra la portada en lugar de analizar las fechas de publicación? Porque muchas fuentes tienen marcas de tiempo no fiables o diseños anti-raspado. "Nuevo en la portada" es un proxy robusto para "noticias en la ventana de hoy".

Protección de ventana de tiempo (determinista, no LLM): Para fuentes de extracción que sí exponen pubDate (RSS/Atom), el escáner aplica un límite estricto antes de difuminar. La ventana predeterminada es de 36 horas; se puede anular con extract_profile.window_hours. Los elementos más antiguos que la ventana se descartan. Los elementos con fechas faltantes o no analizables se excluyen por defecto (missing_date_policy: exclude) porque una fecha que el motor no puede verificar es una fecha en la que no puede confiar. Establezca missing_date_policy: include solo para fuentes donde se sabe que las fechas no son fiables y la difuminación de la portada es la señal principal.

Esta regla existe porque el cumplimiento de la ventana de fecha es una cuestión de teneduría de libros, no de criterio. Debe ser determinista y auditable, nunca delegado a un LLM, que tiende a leer mal las fechas y mezclar historias antiguas en el informe de hoy.

3.2 Editar — preseleccionar con el perfil

Objetivo: puntuar candidatos con reglas baratas; mantener el embudo amplio.

Fórmula:

puntaje = suma(pesos de palabras clave coincidentes)
       + suma(bonos de coincidencia de categorías)
       - suma(pesos negativos coincidentes)

Pasos:

  1. Cargar el último perfil del vertical.
  2. Para cada título candidato:
    • Coincidir palabras clave y categorías (límite de palabra completa para términos ASCII).
    • Restar negativos.
    • Registrar last_hit para cualquier término coincidente.
  3. Umbral: por defecto puntaje >= 2 pasa; puntajes más bajos son rechazados con reject_reason: low_score.
  4. Escribir cada candidato en el registro como un registro item:
    • Pasó → stage: prescreened.
    • Rechazado → stage: rejected, con reject_reason.

Los elementos rechazados son el combustible para la calibración. Nunca los elimine.

3.3 Revisar — segunda pasada estructurada

Objetivo: verificar que los elementos preseleccionados sean noticias reales, sobre el tema, y no anuncios/trabajos.

Pasos:

  1. Ordenar elementos preseleccionados por puntaje (descendente).
  2. Limitar la representación por fuente (por ejemplo, máximo 4 por fuente) para evitar monopolio.
  3. Para cada elemento, obtener el texto del artículo (primeros ~1000 caracteres) y extraer una fecha de publicación mediante una cadena de respaldo:
    • JSON-LD datePublished
    • <meta article:published_time>
  4. Enviar una solicitud por lotes al proveedor LLM configurado. Preguntar por cada elemento:
    • is_news — no es anuncio/trabajo/comunicado
    • is_ad, is_job — descalificadores
    • vertical_fit — puntuación de relevancia de 0 a 1
    • summary — resumen de 2 a 3 oraciones
  5. Aplicar motivos de rechazo:
    • not_news, is_ad, is_job, low_fit.
  6. Escribir los resultados en el registro como registros item con stage: verified o stage: rejected.

Si no hay ningún proveedor LLM configurado: el proceso se ejecuta en modo solo reglas --dry y promueve los elementos preseleccionados directamente.

3.4 Publicar — deduplicar e informar

Objetivo: colapsar duplicados y producir un informe diario legible.

Pasos:

  1. Cargar elementos recientemente agrupados (últimos 14 días, excluyendo hoy).
  2. Deduplicación de dos niveles para elementos verificados:
    • Coincidencia exacta de url_norm → saltar.
    • simhash del título con distancia de Hamming ≤ 3 → mismo evento; agrupar en un clúster.
  3. Para cada clúster, seleccionar el elemento con mayor puntuación como elemento principal; los demás se convierten en fuentes relacionadas.
  4. Ordenar clústeres por recuento de fuentes y puntuación.
  5. Formatear el informe. Añadir un pie de estado:
    • fuentes escaneadas, elementos preseleccionados, rechazados, agrupados, recuento de elementos del informe
    • alertas de salud de fuente
    • tiempos de etapa
  6. Escribir un registro report en el registro.

4. Bucle de reflexión (autoevolución)

Desencadenante: el usuario lee un informe y proporciona retroalimentación, por ejemplo

"Más historias de seguridad de IA, menos publicaciones patrocinadas, y mantén un ojo en la regulación de la UE."

Pasos:

  1. Analizar la retroalimentación en operaciones de perfil:
    • add_keyword: {term, weight}
    • adjust_weight: {term, delta}
    • remove_keyword: {term}
    • add_negative: {term, weight}
    • adjust_negative_weight: {term, delta}
    • remove_negative: {term}
  2. Aplicar operaciones al perfil; incrementar versión.
  3. Escribir un registro evolution en el registro que contenga las operaciones y el texto de retroalimentación original.
  4. Re-verificar elementos recientemente agrupados (últimos 7 días) contra los nuevos negativos/pesos reducidos.
    • Si alguno ahora se filtraría, informar el recuento al usuario.
  5. Devolver un resumen de confirmación.

Regla de decaimiento (semanal):

  • Los términos con origin: learned que no han tenido aciertos en 30 días pierden 1 de peso.
  • Peso 0 → mover a una lista de eliminación pendiente; preguntar al usuario antes de eliminar.
  • Los términos con origin: manual nunca se eliminan automáticamente, solo se advierte.

5. Taxonomía de adquisición de fuentes

Una fuente se puede adquirir de cinco maneras. El motor las trata de manera uniforme una vez que llegan al registro. El registro de fuentes del informe muestra cada fuente como status [nombre](url) · método para que un lector pueda ver de un vistazo cómo se adquirió la fuente.

TipoMecanismoCuándo usarloVisualización en el registro
pullRSS/API/curl en cronFeeds y APIs estables🟢 [Hacker News](https://news.ycombinator.com/rss) · pull
scanDifuminación de portada + preselecciónSPAs, sitios irregulares🟢 [TechCrunch](https://techcrunch.com) · scan
pushWebhook/SSE/puenteAlertas internas o ecosistemas cerrados🟢 [Alertas Internas](...) · push
searchBúsqueda ad-hocDescubrimiento de nuevas fuentes o puesta al día de eventos importantes🟢 [Búsqueda](...) · search
human-feedEl usuario suelta un enlaceConsejos exclusivos y señales de primera mano🟢 Consejo de Weixin · human-feed

Agregue una fuente registrando {id, name, list_url, extract_profile} en la configuración del vertical. Una fuente human-feed establece extract_profile = { method = "human_feed" } y puede omitir list_url.

Human-feed facilitado por el agente

Una variante útil es el human-feed facilitado por el agente: el propio agente realiza una búsqueda en la plataforma (por ejemplo, en X de publicaciones bajo un hashtag de IA en las últimas 24 a 36 horas), selecciona ≥1 candidato y lo inyecta a través del canal human-feed. El elemento inyectado aún pasa por las mismas etapas de preselección, revisión y deduplicación que los elementos pull/scan — human-feed garantiza la entrada al grupo de candidatos, no un pase libre al informe.

"Nunca te detengas en el mensaje"

Una publicación en redes sociales, titular o consejo es una señal, no una cita. Cada elemento inyectado debe resolverse a la URL del artículo original antes de llegar al registro. Si el agente solo puede encontrar una URL de publicación, scripts/x_hunt.py intenta una búsqueda de mejor esfuerzo para el artículo original; si eso falla, el candidato se descarta y la razón se registra en el registro. El informe publicado nunca apunta a los lectores a una publicación o titular como la fuente final.

Implementación de referencia (scripts/x_hunt.py)

scripts/x_hunt.py es una teneduría de libros determinista: escribe un elemento ya seleccionado en el registro. La búsqueda, lectura y selección son trabajo de criterio del agente, realizado con las propias herramientas de búsqueda web del agente.

# Ruta preferida: el agente ya ha resuelto el titular a la URL del artículo original.
python scripts/x_hunt.py --vertical ai-frontier --source-id ainativef_zh \
  --title "OpenAI anuncia GPT-5" \
  --url "https://openai.com/blog/introducing-gpt-5" \
  --inject

# Si solo está disponible una URL de publicación de X, el script intenta resolver la URL original.
python scripts/x_hunt.py --vertical ai-frontier --source-id ainativef_zh \
  --title "OpenAI anuncia GPT-5" \
  --url "https://x.com/OpenAI/status/1234567890" \
  --inject

# Respaldo de búsqueda automatizada de mejor esfuerzo (a menudo bloqueado; úselo con moderación).
python scripts/x_hunt.py --vertical ai-frontier \
  --query "IA inteligencia artificial site:x.com" --inject

# Revisar candidatos de respaldo de búsqueda sin inyectar
python scripts/x_hunt.py --vertical ai-frontier \
  --query "IA inteligencia artificial site:x.com"

El registro inyectado se escribe en el registro como un item con:

  • source_id: el id de fuente registrado (por defecto owner_tips).
  • stage: scanned — entra al proceso en la preselección.
  • facilitated_by: agent — procedencia auditable.

Los registros descartados (URLs de publicaciones no resolubles, candidatos fuera de tema, etc.) también se añaden al registro con stage: dropped y un drop_reason, para que el rastro de auditoría incluya lo que no llegó.

Separación de preocupaciones: el criterio (búsqueda/lectura/selección/resolución de origen) pertenece al agente; la teneduría de libros (normalizar URL, asignar id, añadir al registro) pertenece al script. Esto mantiene la habilidad determinista y deja las estrategias de recuperación específicas de la plataforma a las propias capacidades del agente.

Este modo convierte la plataforma de una fuente de contenido pasiva en una búsqueda activa de descubrimiento de fuentes: cuando el agente encuentra repetidamente buenas historias del mismo medio, ECHO puede preguntar "¿Agregar '' como una fuente rastreada?" y, al responder sí, promover el medio a una fuente formal de pull/scan. Ese bucle cerrado es la autoevolución de la habilidad en acción.


6. Tipos de registros del registro

Cada línea del registro es un objeto JSON con un campo type.

typecampos
sourceid, name, vertical, list_url, extract_profile, health
frontpagesource_id, date, items[], count
profilevertical, version, keywords[], negatives[], categories[], reason
itemid, vertical, source_id, title, url, url_norm, stage, scores, reject_reason, simhash, cluster_id
reportdate, vertical, item_ids[], generated_at, stats
feedbackdate, vertical, text, applied_ops[], status
evolutionvertical, from_version, to_version, ops[], reason, date

7. Ejecutar la implementación de referencia

# Ejecución solo con reglas (no requiere LLM)
python -m engine.pipeline --dry --vertical tech --config config/example_vertical.toml

# Con revisión LLM
export APERTURE_LLM_API_KEY="sk-..."
python -m engine.pipeline --vertical tech --config config/example_vertical.toml

# Aplicar retroalimentación
python -c "from engine.feedback import apply_feedback; apply_feedback('Más seguridad de IA, menos anuncios', 'tech')"

Después de publicar, opcionalmente ejecute ECHO para hacer al usuario hasta dos preguntas de aclaración:

from engine.echo import ask

questions = ask("tech")
for q in questions:
    print(q["question"])

# Más tarde, aplicar una respuesta de una palabra: yes / no / skip / silence
from engine.echo import apply_answer
apply_answer(question_id, "tech", "yes")

8. ECHO — aclaración proactiva

ECHO es una capa proactiva opcional que hace al usuario hasta dos preguntas de aclaración de una palabra después de cada informe. Convierte a los lectores pasivos en entrenadores de perfil activos.

ECHO está intencionalmente

Skills relacionados