Gabriel Neuman
Gabriel Neuman
ResearchPúblico

/escucha

Trae lo que publicó esta semana la gente que vigilamos — Reddit, YouTube (con transcript y comentarios), LinkedIn y las newsletters del inbox. Lee content/escucha/watchlist.md, pregunta qué fuentes correr y entrega Top Señales agrupadas por fuente, rankeadas por relevancia al negocio con la rúbrica de content/escucha/senales.md. No escribe archivo. Activar cuando el usuario diga /escucha, 'qué están publicando', 'qué dice Reddit de X', 'qué publicó <canal> esta semana', 'revisa mis newsletters', 'brief de la semana'.

Cómo invocarlo

Slash command directo o cualquiera de estas frases naturales:

/escuchaqué están publicandoqué dice reddit derevisa mis newslettersbrief de la semanaqué publicó esta semana

Hereda de

Este skill carga automáticamente las reglas de:

/voz-gnb

SKILL.md completo

skills/escucha/SKILL.md

Este es el archivo real que opera en producción. Cópialo, ábrelo en Claude para adaptarlo, o léelo en crudo:

escucha — Qué está diciendo el mercado

Captura multi-fuente de lo que publicaron los que vigilamos. Escucha lo que
dicen
, no lo que hacen: contrataciones, funding y lanzamientos son intención y
hoy no se cubren.

Salida en sesión: Top Señales agrupadas por fuente, hasta 5 por fuente,
rankeadas por relevancia al negocio y qué tan reciente — no por engagement
con 2 a 4 líneas de análisis debajo de cada bloque. Nada más. La tabla cruda es
la Parte 2 y solo sale si la piden. No se escribe ningún archivo.

Fuentes

Tres corren por scripts/escucha.py con --source. Gmail es la excepción: no
tiene script
, se lee con las tools MCP del conector.

Fuente Costo Necesita
reddit gratis nada
youtube gratis yt-dlp en el PATH
linkedin cobra por post raspado APIFY_API_KEY
gmail gratis conector Gmail autorizado en claude.ai

A quién vigilamos: content/escucha/watchlist.md, en ## LinkedIn,
## YouTube, ## Reddit y ## Gmail.
Qué cuenta como señal: content/escucha/senales.md. Es la autoridad
su lista de temas y su lista de ignorar mandan sobre tu juicio.

No-negociables

  1. Nunca correr todas las fuentes por default. Preguntar primero (paso 1).
  2. LinkedIn cobra. --dry-run antes de cualquier corrida con más de 3
    líneas. Imprime max_posts_scraped sin gastar.
  3. "No encontró nada" y "no se pudo leer" son cosas distintas. Un perfil
    inalcanzable, un subreddit con rate limit o Gmail sin conectar se reportan
    como tales. Nunca se leen como "estuvo callado". El stderr del script dice
    cuál es cuál — hay que leerlo.
  4. El engagement es desempate, nunca la llave de orden.
  5. Nunca mezclar fuentes en una lista o una tabla. Las vistas de YouTube no
    son upvotes ni reacciones.
  6. Cero invención. Si no vino en el JSON, no existe. Ni un post, ni una URL,
    ni un número. Un conteo desconocido es ?, nunca 0.
  7. Voz GNB vía extends: [voz-gnb]. El análisis pasa por VOICE GATE; los
    nombres de herramientas y las citas textuales quedan como son.
  8. No se escribe archivo. Si el usuario quiere una pieza, eso es /blog,
    /newsletter-gnb o /redes — otra tarea. Cuando la pieza es la
    newsletter, las ligas de esta corrida son la materia prima de su sección
    Fuentes: ahí manda la regla de qué se cita, no aquí.

Paso 1 — Preguntar

Con AskUserQuestion (multiSelect: true), ofreciendo solo las fuentes que
tengan entradas en su sección y su llave disponible. Decir cuántas entidades
vigila cada una y cuál cobra.

Saltar la pregunta cuando el usuario ya nombró la fuente ("revisa Reddit"). Si
la pregunta es de tema sin fuente ("qué dicen de los agentes"), es modo
búsqueda: preguntar si va a Reddit, YouTube o las dos.

Gmail lee el correo del usuario, así que nunca se ofrece para una pregunta de
tema abierto y nunca corre sin que lo pidan. Si el conector no está autorizado
—las tools search_threads / get_thread no aparecen en la sesión— ofrecerlo
etiquetado "falta conectar" y, si lo eligen, mandarlos a claude.ai → Settings →
Connectors → Gmail → Connect. Es un flujo de navegador que no puedes hacer por
ellos: nunca pidas un token, un código ni una contraseña de aplicación. Si
dicen que no, se salta y no se vuelve a mencionar.

Con Reddit hay que decidir qué vigila antes de correr: un tema (-q) o los
subreddits del watchlist. Inferirlo cuando la frase ya lo decide —un asunto es
-q, un subreddit nombrado es modo feed— y meterlo en la misma pregunta.

Paso 2 — Correr

python3 scripts/escucha.py --source reddit -d 7 -n 25 --enrich 5
python3 scripts/escucha.py --source reddit -q "agentes de ia"
python3 scripts/escucha.py --source youtube -d 30 -n 15 --per-source 8 --enrich 3
python3 scripts/escucha.py --source youtube -q "claude code" --enrich 3
python3 scripts/escucha.py --source linkedin --dry-run
python3 scripts/escucha.py --source linkedin -d 7 -n 25 --per-source 10

Todas imprimen {"source","count","signals":[...]} en stdout, ya ordenadas:
por engagement en Reddit y LinkedIn, por fecha en YouTube. Las notas por entidad
van a stderr. El JSON es para ti — nunca lo pegues en el chat. Las fuentes
son independientes: córrelas en paralelo.

Reddit

Gratis, así que córrelo sin miedo; el único costo es tiempo. Las peticiones van
~2s aparte para no pegarle al rate limit, así que cinco subreddits tardan un par
de minutos. Eso no es que se colgó.

Dos modos, y contestan preguntas distintas:

  • Modo tema (-q) busca en todo Reddit y es el fuerte. Alcanza mucho más
    allá del watchlist. Úsalo cuando nombren un asunto, una marca o un competidor.
  • Modo subreddit (sin -q) lee los feeds del watchlist. Rankea por
    engagement crudo, así que en subs grandes saca lo más relatable, no lo más
    relevante. Filtra duro contra senales.md.

Pasa palabras clave, no la oración del usuario. La calidad de la query es lo
que decide la relevancia:

Pide Pasa No
"qué se dice de los agentes de IA" -q "agentes de ia" -q "qué se dice de los agentes de IA"
"monitorea menciones de Taplio" -q "Taplio" -q "monitorea menciones de Taplio"

Con una marca o competidor, reporta toda mención sin importar el score: un
prospecto diciendo que canceló a un competidor importa con cero upvotes.

--enrich (default 5) es cuántos posts top traen su hilo de comentarios. Los
comentarios son donde el dolor se dice con nombre y precio
— léelos.

Los upvotes vienen de un snapshot del archivo tomado cerca de la publicación,
mientras que los scores de comentarios son vivos. Un post con score_note trae
el conteo subido al de su mejor comentario: trátalo como piso, no como medición,
y no lo cites como exacto. upvotes_stale guarda el original.

Un subreddit que aparece bajo no posts from ... en stderr tuvo rate limit o
está inalcanzable — no estuvo callado. Dilo en la Parte 1.

YouTube

Gratis y sin llave, pero necesita yt-dlp (python3 -m pip install yt-dlp); si
falta, el script lo dice y se sale. Es lento por naturaleza: descubrimiento por
canal, luego metadata en lote, luego dos llamadas más por video enriquecido.
Presupuesta unos minutos y no lo trates como colgado.

Se ordena por fecha, lo más nuevo primero. Las vistas solo desempatan entre
videos del mismo día. Es a propósito: un video viejo con 500 mil vistas no es
noticia, y la subida de esta semana con 400 vistas de un competidor sí. No lo
reordenes por vistas al reportar.

Amplía la ventana: los canales publican semanal en el mejor caso, así que -d 7
suele volver vacío y -d 30 es el default útil.

--enrich (default 5) es cuántos videos top traen transcript y comentarios.
Esa es la razón de usar la fuente. Lee el transcript antes de rankear — el
título vende el clic, el transcript es lo que de verdad se dijo, y ahí es donde
un competidor nombra su precio o su modelo de entrega. Cita del transcript, no
del título.

Un video con transcript_unavailable no tenía subtítulos o lo estrangularon:
dilo, no lo trates como que no dijo nada. Los que quedaron abajo del corte de
--enrich simplemente no traen la llave transcript — eso es presupuesto, no
falla, y nunca se reportan como mudos.

El engagement aquí es views, nunca una suma: las vistas aplastan a los likes
por órdenes de magnitud. views, likes y comments van reportados aparte, y
un null es conteo oculto, no cero.

LinkedIn — la que cobra

--per-source (default 10) topa los posts por línea del watchlist. Una corrida
raspa como máximo líneas × --per-source, y eso es la cuenta. -d filtra
después de traer, así que achicar la ventana no ahorra nada — baja
--per-source. --dry-run es gratis e imprime el costo máximo.

Proveedor intercambiable con --linkedin-provider, como lib/proveedores/:
apify funciona hoy; unipile está declarado y sin implementar, y falla
diciendo qué variable falta. Si Gabriel consigue las credenciales de Unipile, se
implementa ahí y el resto del sistema no se entera.

Lee el stderr: un perfil que no devolvió nada está inalcanzable o inactivo,
nunca "callado".

La sección ## LinkedIn del watchlist está vacía a propósito — los archivos de
research no traen URLs de LinkedIn y adivinar una raspa a la persona equivocada
y la cobra igual. Si el usuario quiere LinkedIn, pídele las URLs.

Gmail — sin script, con las tools MCP

Solo lectura, siempre. Usa search_threads, get_thread y get_message, y
nada más.
El conector también expone enviar, responder, borradores, etiquetas,
papelera y spam: ninguna de esas pertenece a este skill. La escucha lee;
nunca escribe, nunca marca como leído, nunca etiqueta.

El watchlist trae nombres, no direcciones. Resuelve cada nombre a sus
direcciones reales con una búsqueda amplia sobre sus palabras distintivas:

from:(smart OR creator OR samy) newer_than:90d

Espera más de una dirección por nombre: Substack manda desde una dirección
por publicación, con el patrón nombre + publicacion en el buzón. Toma todas
las que claramente son de esa publicación y di cuáles emparejaste al
reportar, para que un mal match se vea. Si un nombre no resuelve a nada, dilo y pide un número
reenviado en vez de adivinar una dirección.

Alcance: dos anillos, ambos acotados. Ya resuelto, toda query va clavada a
esas direcciones más las categorías de newsletter:

from:(REMITENTE_1 OR REMITENTE_2) newer_than:7d
{category:promotions category:updates} newer_than:7d -in:sent

Nunca ampliar más allá de esos dos. Un barrido de la bandeja, in:anywhere,
un from: a una persona, o buscar en la categoría principal lee correo personal
y de clientes, y este skill no hace eso — sin importar cómo esté formulada la
pregunta. Una pregunta de tema se contesta agregando términos dentro de los
dos anillos, nunca quitándolos.

Lo que las categorías saquen y claramente no sea newsletter —un recibo, un aviso
de calendario, un reset de contraseña, un hilo personal que cayó en updates— se
descarta sin resumirlo ni citarlo. Di cuántos descartaste, no cuáles eran.

Una llamada por nombre para resolver, luego una sola para todo el watchlist.
Usa view: THREAD_VIEW_MINIMAL para que el listado traiga asunto y snippet,
rankea con eso, y solo llama get_thread con messageFormat: "PLAIN_TEXT" a
los mejores. PLAIN_TEXT convierte el HTML a texto, que es justo la razón de no
escribir un script.

Ese segundo paso es el --enrich de Gmail: 5 números por default. Los
cuerpos son largos y traer veinte completos acaba el contexto antes de escribir
el reporte. Los que quedan abajo del corte se reportan desde asunto y snippet, y
se marca en una palabra — es presupuesto, no falla, y nunca se llaman vacíos.

newer_than:7d es el equivalente de -d. Ampliar como YouTube: la mayoría son
semanales, así que newer_than:30d suele servir más.

Dale la misma forma que a las demás fuentes para que el paso 3 la trate igual:
entity es el nombre del watchlist, author el remitente, text el cuerpo en
texto plano, date la fecha de recepción y url el permalink del hilo
(https://mail.google.com/mail/u/0/#inbox/<threadId>).

engagement es siempre null en Gmail: una newsletter no reporta conteos
públicos. Escribe en la tabla, nunca 0, y nunca inventes una tasa de
apertura. Se ordena por fecha, lo más nuevo primero.

Paso 3 — Reportar

Todo va agrupado por fuente. Una corrida de Reddit y YouTube produce un
bloque de Reddit y uno de YouTube, en el mismo formato. Ordena los bloques por
cuánto devolvieron, el mayor primero, y adentro usa el orden propio de la
fuente.

Parte 1 — Top Señales, por fuente

Encabeza cada bloque con la fuente, su ventana y su conteo:

**Reddit** — 7 días, 34 posts, 6 que valen

Luego hasta 5 posts por fuente (no 5 en toda la corrida), rankeados por
relevancia al negocio y luego por qué tan reciente. Un post de 30,000 de
engagement fuera del nicho no entra; uno de 90 de un competidor directo
describiendo su modelo de entrega, sí.

content/escucha/senales.md es la autoridad. Si no existiera, cae a la ficha de
negocio de CLAUDE.md y di una vez que llenarlo afila las siguientes corridas.

Los comentarios de Reddit y YouTube le ganan al texto del post. Cuando un
item trae top_comments, léelos antes de rankear: en las respuestas alguien
dice el precio que pagó, nombra a la agencia que corrió, o admite el problema
que el post solo insinúa. Cita un comentario cuando diga algo que el post no, y
atribúyelo a quien lo escribió.

Formato de cada post, una línea:
<Autor> — <eng> — <qué dice el post> — <liga>

Debajo, 2 a 4 líneas de análisis solo de esa fuente: qué están publicando y
qué venden por debajo, qué se repite, qué es nuevo contra lo que ya venía, dónde
los números dicen algo que el texto no. Cada afirmación amarrada a un post o un
número concreto — cero consejo genérico de marketing de contenidos. Menciona
brevemente cuando los posts de mayor engagement de esa fuente se hayan excluido
por estar fuera de tema, para que la omisión se vea.

Menos de 5 en un bloque es correcto cuando la fuente vino flaca — nunca
rellenes.
Una fuente que no calificó nada recibe una línea diciéndolo y su
bloque igual aparece
, para que el silencio se vea en vez de faltar.

Con dos o más fuentes, cierra con hasta 3 líneas de cruce: qué aparece en más
de un lado y dónde se contradicen. Es el único lugar donde se comparan fuentes.

Cierra con una línea, máximo, de qué vale la pena hacer, y solo si los datos
la sostienen. No lo conviertas en un memo de estrategia.

Y ahí párate. Termina el turno con una línea ofreciendo el resto, nombrando
qué queda guardado por fuente: "Guardados: 28 posts más de Reddit, 11 de
YouTube — dime y saco las tablas."
No uses AskUserQuestion para esto: es una
oferta, no una pregunta que bloquea.

Lo que devolvió vacío, tronó, se reintentó o trajo duplicados va en el bloque
de su fuente
, no guardado con la tabla.

Parte 2 — Tablas crudas, por fuente (solo si las piden)

No las imprimas por default. Cuestan muchos tokens y las Top Señales suelen
contestar la pregunta solas. Solo cuando pidan "tabla completa", "muéstrame
todo" o pregunten por posts fuera del top.

Una tabla por fuente, nunca una mezclada. Cada una con su orden. Encabeza con
fuente, ventana y cuántos de cuántos se muestran.

Cada tabla es un extracto: las 15 filas top por fuente, y una línea abajo
nombrando el resto — "19 posts más de Reddit en la corrida — pide el resto."
Solo si vuelven a pedir imprimes todas. Una fuente con 15 o menos ya está
completa: imprímela entera y no digas nada de resto.

El extracto se toma directo del orden, incluyendo los que quedaron fuera de tema
— eso es lo que hace visible el corte.

Columnas, en este orden, en todas:

Autor Eng Desglose Resumen Liga
  • Autor — el author, no el entity del watchlist. En Reddit es el
    redditor y el subreddit va en el resumen; en YouTube es el canal; en Gmail el
    nombre de la newsletter, no la dirección.
  • Eng — el número de engagement, dígitos pelones. Un null es ?,
    nunca 0. En YouTube son vistas. En Gmail no hay número: en toda la
    columna.
  • Desglose<upvotes>/<comentarios> en Reddit,
    <reacciones>/<comentarios>/<compartidos> en LinkedIn,
    <vistas>/<likes>/<comentarios> en YouTube. En Gmail va la fecha de recepción
    YYYY-MM-DD, que es por lo que está ordenada.
  • Resumen — 1 o 2 oraciones de qué dice el post, ~200 caracteres. Prefiere lo
    concreto: números, nombres de herramientas, precios. No por qué importa ni
    qué hacer — eso fue la Parte 1.
  • Liga — liga markdown etiquetada liga.

Prohibido dentro de las tablas: temas, agrupaciones, patrones entre posts,
lecturas competitivas, oportunidades y recomendaciones. Las filas son
descriptivas. Orden estricto por la llave de la fuente.

El JSON de la corrida sigue disponible toda la sesión: una petición posterior se
contesta desde ahí. Nunca vuelvas a correr el script para rearmar una tabla
— una re-corrida de LinkedIn cobra otra vez.

Límite conocido

scripts/escucha.py pega a reddit.com, arctic-shift.photon-reddit.com,
youtube.com y api.apify.com. Ninguno de los cuatro está permitido por la
política de red de las sesiones de Claude Code en la nube
(el proxy contesta
403 al CONNECT). El script corre bien en la laptop y en cualquier runner con
salida abierta; en una sesión web devuelve count: 0 con el 403 en stderr.

Si estás en la nube y las cuatro fuentes vuelven vacías con 403, no es el
watchlist ni el script
: dilo así y ofrece correrlo en local. Gmail sí funciona
en la nube — el conector no pasa por ese proxy.

Antes de entregar — GATE

  • ¿Preguntaste qué fuentes antes de correr?
  • ¿Corriste --dry-run si LinkedIn traía más de 3 líneas?
  • ¿Leíste el stderr de cada corrida y separaste "vacío" de "no se pudo leer"?
  • ¿Leíste los top_comments y los transcript antes de rankear?
  • ¿El orden es relevancia primero y engagement solo como desempate?
  • ¿Cada fuente tiene su bloque, aunque no haya calificado nada?
  • ¿Cero números inventados? ¿Los desconocidos van como ? y no como 0?
  • ¿VOICE GATE de voz-gnb sobre el análisis?
  • ¿No escribiste ningún archivo?

Skills relacionados

El Skill Stack GNB

Deja de promptear a mano

Este skill es una pieza. El stack completo son agentes con nombre que viven en tu repo, hablan con tu voz y cobran con tu pricing — con un bloque [CUSTOMIZE] que editas una vez y quedan tuyos. Empieza por el documento gratis.