Communitygithub.com

Varnan-Tech/opendirectory

Proporciona la URL o descripción de tu producto. Encuentra tus 5 principales competidores, investiga sus canales de PR (editoriales, podcasts, comunidades), identifica los más recurrentes, busca al periodista o anfitrión de cada uno y devuelve una lista segmentada de contactos con ángulos de historia y borradores de propuestas frías listos para enviar, adaptados a tu producto. Úsalo cuando te pidan encontrar oportunidades de PR, descubrir dónde aparecieron competidores, crear una lista de contactos de medios, buscar periodistas que cubran tu sector u obtener plantillas de propuestas para cobertura de prensa.

¿Qué es opendirectory?

Esta habilidad transforma cualquier URL de producto o descripción en una estrategia completa de relaciones públicas. Su funcionamiento es meticuloso: primero, descubre 5 competidores directos mediante búsquedas en Tavily; luego, realiza una investigación de PR en tres vertientes (editorial, podcasts y comunidades) para cada competidor, identificando dónde han obtenido cobertura. A continuación, analiza los patrones cruzados para determinar los canales más efectivos (de nivel 1, 2 o 3 según el número de competidores que aparecen en ellos) y extrae ángulos de historia específicos de los títulos de artículos y episodios. Finalmente, genera una lista de contactos segmentada por nivel, que incluye el nombre del periodista o anfitrión, el medio y un borrador de propuesta fría personalizado para tu producto. Está diseñada para evitar alucinaciones: cada nombre, canal y ángulo debe estar respaldado por un resultado de búsqueda verificable. Es compatible con agentes como Claude Code, Cursor y Codex que ejecuten scripts de shell y Python, y requiere una clave API de Tavily para funcionar (con Firecrawl como opción para obtener páginas de productos).

Compatible con✓Claude Code~Codex CLI~Cursor✓Gemini CLI
npx skills add https://github.com/Varnan-Tech/opendirectory/tree/main/skills/competitor-pr-finder

Preguntar en tu IA favorita

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

Documentación

Buscador de PR de Competidores

Proporciona la URL de tu producto. Encuentra tus competidores, investiga cada canal de PR que utilizaron (noticias, podcasts, comunidades), identifica los canales que aparecen en múltiples competidores (tus objetivos probados), localiza al periodista o anfitrión de cada uno y redacta una propuesta fría personalizada para tu producto en cada canal de nivel 1.


Política de cero alucinaciones: Cada canal, nombre de periodista, ángulo de historia y detalle de la propuesta en el resultado debe rastrearse hasta un resultado de búsqueda específico de Tavily o la página del producto obtenida. Esto aplica para:

  • Nombres de competidores: deben aparecer en los resultados de búsqueda de Tavily, no en el conocimiento de entrenamiento de la IA
  • Nombres de canales: deben tener una URL en los resultados de búsqueda
  • Nombres de periodistas/anfitriones: deben aparecer textualmente en un fragmento de Tavily
  • Ángulos de historia: extraídos únicamente de títulos de artículos/episodios en los resultados de búsqueda
  • Borradores de propuestas: deben hacer referencia a evidencia específica de los datos de búsqueda + análisis del producto

Errores Comunes

El agente tenderá a...Por qué está mal
Mencionar un periodista a partir del conocimiento de entrenamientoCada nombre de periodista debe rastrearse hasta un fragmento de resultado de búsqueda. Escribir "Sarah Perez cubre startups en TechCrunch" de memoria es una alucinación.
Listar canales sin URLs de evidenciaCada canal en el resultado debe tener al menos una URL de los resultados de búsqueda de PR que demuestre que un competidor apareció allí.
Saltarse el paso de confirmación de competidoresSiempre muestra los competidores descubiertos y espera a que el usuario los confirme. Competidores incorrectos = búsquedas desperdiciadas y un resultado inútil.
Generar propuestas genéricas ("Nos encantaría aparecer")Cada propuesta debe hacer referencia a un ángulo específico de la evidencia Y a un diferenciador específico del análisis del producto.
Marcar un canal como Nivel 1 con solo 1 ocurrencia de competidorNivel 1 = 3+ competidores. Nivel 2 = exactamente 2. Nivel 3 = 1. No promociones canales que no hayan demostrado su valor.
Usar guiones largos en el resultadoReemplaza todos los guiones largos (—) por guiones comunes (-).

Leer Archivos de Referencia Antes de Cada Ejecución

cat references/pr-channel-types.md
cat references/pitch-guide.md
cat references/tier-scoring.md

Paso 1: Verificación de Configuración

echo "TAVILY_API_KEY:    ${TAVILY_API_KEY:+set}${TAVILY_API_KEY:-NO ESTABLECIDA -- requerida}"
echo "FIRECRAWL_API_KEY: ${FIRECRAWL_API_KEY:+set}${FIRECRAWL_API_KEY:-no establecida, se usará Tavily extract como respaldo}"

Si falta TAVILY_API_KEY: Detente inmediatamente. Dile al usuario: "TAVILY_API_KEY es necesaria para investigar competidores y encontrar cobertura de PR. No hay respaldo. Consíguela en app.tavily.com -- nivel gratuito: 1000 créditos/mes (aproximadamente 43 ejecuciones completas a ~23 búsquedas/ejecución). Agrégala a tu archivo .env."

Si solo falta FIRECRAWL_API_KEY: Continúa. Se usará Tavily extract para la obtención de la URL.


Paso 2: Analizar la Entrada

Recopila de la conversación:

  • product_url: la URL a obtener (requerida, a menos que el usuario pegue una descripción directamente)
  • product_name: opcional, derivado de la página si no se proporciona
  • geography: opcional -- EE. UU. / Europa / global. Valor predeterminado: EE. UU.

Si el usuario proporciona solo una descripción pegada (sin URL): Omite los Pasos 3 y 4. Ve directamente al Paso 4 (análisis del producto) usando el texto pegado como product_content. Establece page_source como user_description y anótalo en data_quality_flags.

Si no hay ni URL ni descripción: Pregunta: "¿Cuál es la URL de tu producto o startup? O pega una breve descripción: qué hace, para quién es y qué lo diferencia de los competidores."

Deriva el slug del producto:

PRODUCT_SLUG=$(python3 -c "
from urllib.parse import urlparse
import sys
url = 'URL_HERE'
if url.startswith('http'):
    host = urlparse(url).netloc.replace('www.', '')
    print(host.split('.')[0])
else:
    import re
    print(re.sub(r'[^a-z0-9]', '-', url[:30].lower()).strip('-'))
")
echo "Slug del producto: $PRODUCT_SLUG"

Paso 3: Obtener la Página del Producto

Principal: Firecrawl (si FIRECRAWL_API_KEY está establecida)

curl -s -X POST https://api.firecrawl.dev/v1/scrape \
  -H "Authorization: Bearer $FIRECRAWL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "URL_HERE", "formats": ["markdown"], "onlyMainContent": true}' \
  | python3 -c "
import sys, json
d = json.load(sys.stdin)
content = d.get('data', {}).get('markdown', '') or d.get('markdown', '')
print(f'Obtenido via Firecrawl: {len(content)} caracteres')
open('/tmp/cprf-product-raw.md', 'w').write(content)
"

Respaldo: Tavily extract (si FIRECRAWL_API_KEY no está establecida)

curl -s -X POST https://api.tavily.com/extract \
  -H "Content-Type: application/json" \
  -d "{\"api_key\": \"$TAVILY_API_KEY\", \"urls\": [\"URL_HERE\"]}" \
  | python3 -c "
import sys, json
d = json.load(sys.stdin)
content = d.get('results', [{}])[0].get('raw_content', '')
print(f'Obtenido via Tavily extract: {len(content)} caracteres')
open('/tmp/cprf-product-raw.md', 'w').write(content)
"

Punto de control:

python3 -c "
content = open('/tmp/cprf-product-raw.md').read()
if len(content) < 200:
    print('ERROR: se obtuvieron menos de 200 caracteres')
else:
    print(f'Contenido OK: {len(content)} caracteres')
"

Si el contenido tiene menos de 200 caracteres: Deja de obtener. Dile al usuario: "La página del producto no devolvió contenido legible; es probable que el sitio use renderizado JavaScript y haya bloqueado la obtención. Por favor, pega una breve descripción directamente: qué hace, para quién es y qué lo diferencia."


Paso 4: Análisis del Producto (IA)

Imprime el contenido de la página:

python3 -c "
content = open('/tmp/cprf-product-raw.md').read()[:5000]
print('=== PÁGINA DEL PRODUCTO (primeros 5000 caracteres) ===')
print(content)
"

Instrucciones para la IA: Analiza la página del producto anterior y extrae:

  • product_name: el nombre del producto o empresa
  • one_line_description: qué hace, para quién, propuesta de valor central. Menos de 20 palabras. Sin lenguaje de marketing. Ejemplo: "Automatización de CI/CD para equipos de desarrolladores que autogestionan sus pipelines."
  • industry_taxonomy: l1 (nivel superior: ej. herramientas de desarrollo / fintech / healthtech / consumo), l2 (sector: ej. devops / pagos / telemedicina), l3 (nicho específico: ej. automatización de CI/CD / pagos integrados / consulta de video asíncrona). Etiquetas vagas como "tecnología" por sí solas no son aceptables.
  • differentiators: exactamente 2-3 cosas específicas que distinguen este producto de los competidores genéricos. Estos se alimentan directamente a los borradores de propuestas; sé específico. Ejemplo: ["Ejecutor de pipeline autogestionado -- ningún dato sale de tu infraestructura", "Soporte nativo para monorepos con generación dinámica de pasos"]
  • icp: buyer_persona (título del puesto), company_type (tipo de empresa), company_size (tamaño de la empresa)
  • geography_bias: EE. UU. / Europa / global / no claro
  • page_source: "live_page" o "user_description"

Escribe en /tmp/cprf-product-analysis.json:

python3 << 'PYEOF'
import json

analysis = {
    # COMPLETA a partir de tu análisis anterior
    "product_name": "",
    "one_line_description": "",
    "industry_taxonomy": {"l1": "", "l2": "", "l3": ""},
    "differentiators": [],
    "icp": {"buyer_persona": "", "company_type": "", "company_size": ""},
    "geography_bias": "EE. UU.",
    "page_source": "live_page"
}

json.dump(analysis, open('/tmp/cprf-product-analysis.json', 'w'), indent=2)
print('Análisis del producto escrito.')
PYEOF

Verifica:

python3 -c "
import json
a = json.load(open('/tmp/cprf-product-analysis.json'))
print('Producto:', a['product_name'])
print('Industria:', a['industry_taxonomy']['l1'], '>', a['industry_taxonomy']['l2'], '>', a['industry_taxonomy']['l3'])
print('Diferenciadores:')
for d in a['differentiators']:
    print(f'  - {d}')
"

Paso 4b: Fase 1 -- Descubrimiento de Competidores

ls scripts/research.py 2>/dev/null && echo "script encontrado" || echo "ERROR: no se encontró scripts/research.py -- no se puede continuar"
python3 scripts/research.py \
  --phase discover \
  --product-analysis /tmp/cprf-product-analysis.json \
  --tavily-key "$TAVILY_API_KEY" \
  --output /tmp/cprf-competitors-raw.json

Imprime los resultados para revisión de la IA:

python3 -c "
import json
data = json.load(open('/tmp/cprf-competitors-raw.json'))
print(f'Búsquedas realizadas: {len(data[\"competitor_searches\"])}')
for s in data['competitor_searches']:
    print(f'\nConsulta: {s[\"query\"]}')
    print(f'Respuesta: {s.get(\"answer\",\"\")[:400]}')
    for r in s.get('results', [])[:5]:
        print(f'  - {r[\"title\"]} | {r[\"url\"]}')
        print(f'    {r.get(\"content\",\"\")[:200]}')
"

Instrucciones para la IA: Lee los resultados de búsqueda anteriores. Elige exactamente 5 empresas competidoras que:

  1. Aparezcan en los títulos, respuestas o fragmentos de los resultados de búsqueda
  2. Estén en el mismo nicho L3 que el producto que se analiza
  3. Sean productos competidores reales (no agencias, consultorías o artículos de listas)
  4. Sean distintas entre sí (no la misma empresa con diferentes nombres)

Para cada competidor, escribe: name, url (del resultado de búsqueda donde apareció), description (una oración del fragmento), source_url (la URL del resultado de búsqueda donde se encontraron).


Paso 5: Confirmación de Competidores

Muestra los competidores descubiertos al usuario:

python3 << 'PYEOF'
import json

analysis = json.load(open('/tmp/cprf-product-analysis.json'))

# COMPLETA: 5 competidores de los resultados de búsqueda anteriores
candidates = [
    # {"name": str, "url": str, "description": str, "source_url": str}
]

print(f"\nSe encontraron 5 competidores para {analysis['product_name']} en {analysis['industry_taxonomy']['l3']}:\n")
for i, c in enumerate(candidates, 1):
    print(f"  {i}. {c['name']} -- {c['description']}")
    print(f"     {c['url']}")

data = json.load(open('/tmp/cprf-competitors-raw.json'))
data['competitor_candidates'] = candidates
json.dump(data, open('/tmp/cprf-competitors-raw.json', 'w'), indent=2)
PYEOF

Dile al usuario: "Estos son los 5 competidores que investigaré para cobertura de PR. Agrega, elimina o intercambia cualquiera, o di 'se ve bien' para continuar."

Espera la confirmación. Si el usuario edita la lista (agrega/elimina/intercambia), actualiza los candidatos en consecuencia. Luego escribe la lista confirmada:

python3 << 'PYEOF'
import json

# COMPLETA: lista de competidores confirmada (después de la revisión del usuario)
confirmed = [
    # {"name": str, "url": str}
]

json.dump({"confirmed_competitors": confirmed}, open('/tmp/cprf-competitors-confirmed.json', 'w'), indent=2)
print(f"Se confirmaron {len(confirmed)} competidores para la investigación de PR.")
for c in confirmed:
    print(f"  - {c['name']} ({c['url']})")
PYEOF

Paso 6: Investigación de PR en Tres Vertientes (Fase 2)

python3 scripts/research.py \
  --phase pr-research \
  --competitors /tmp/cprf-competitors-confirmed.json \
  --product-analysis /tmp/cprf-product-analysis.json \
  --tavily-key "$TAVILY_API_KEY" \
  --output /tmp/cprf-pr-raw.json

Esto ejecuta 3 búsquedas por competidor (15 en total):

  • Vertiente A (Editorial): "[competidor]" featured press coverage TechCrunch Forbes Wired article interview
  • Vertiente B (Podcasts): "[competidor]" founder CEO podcast interview appeared on episode
  • Vertiente C (Comunidades): "[competidor]" site:reddit.com OR site:news.ycombinator.com OR site:producthunt.com

Imprime el resumen de cobertura:

python3 -c "
import json
data = json.load(open('/tmp/cprf-pr-raw.json'))
print(f'Competidores investigados: {data[\"competitors_researched\"]}')
print()
for r in data['results']:
    print(f'{r[\"competitor\"]}:')
    for track, tdata in r['tracks'].items():
        n = len(tdata.get('results', []))
        print(f'  {track:12}: {n} resultados')
"

Si las 3 vertientes para un competidor devuelven 0 resultados: Este competidor tiene muy poca cobertura de prensa. Anótalo en data_quality_flags y continúa -- el patrón entre competidores aún funcionará con los 4 restantes.


Paso 7: Análisis de Patrones (IA)

Imprime todos los resultados de PR sin procesar:

python3 -c "
import json
data = json.load(open('/tmp/cprf-pr-raw.json'))
for r in data['results']:
    print(f'\n=== {r[\"competitor\"]} ===')
    for track, tdata in r['tracks'].items():
        print(f'\n--- Vertiente {track.upper()} ---')
        print(f'Consulta: {tdata[\"query\"]}')
        print(f'Respuesta: {tdata.get(\"answer\",\"\")[:400]}')
        for item in tdata.get('results', [])[:5]:
            print(f'  Título: {item[\"title\"]}')
            print(f'  URL:   {item[\"url\"]}')
            print(f'  Fragmento: {item.get(\"content\",\"\")[:200]}')
"

Instrucciones para la IA: Lee TODOS los resultados de búsqueda anteriores. Construye un mapa de frecuencia de canales.

Paso 1 -- Normaliza las URLs al dominio raíz: https://techcrunch.com/2023/06/article-title → techcrunch.com. https://open.spotify.com/episode/... → identifícalo como podcast (episodio de spotify). https://www.reddit.com/r/devops/ → reddit.com/r/devops.

Paso 2 -- Cuenta las ocurrencias: ¿Cuántos competidores diferentes aparecieron en los resultados de cada dominio raíz de canal? Un canal que aparece en la Vertiente A del Competidor A Y en la Vertiente A del Competidor B cuenta como frecuencia 2.

Paso 3 -- Clasifica los canales (sigue references/tier-scoring.md):

  • Nivel 1: apareció en 3+ competidores
  • Nivel 2: apareció en exactamente 2 competidores
  • Nivel 3: apareció en 1 competidor

Paso 4 -- Extrae ángulos de historia de los títulos de artículos/episodios en los resultados. Clasifica cada uno como: anuncio-de-financiación / lanzamiento-de-producto / historia-del-fundador / artículo-de-tendencia / creación-de-categoría / guía / comparación / premio. No infieras; solo clasifica ángulos visibles en los títulos.

Paso 5 -- Clasifica el tipo de canal para cada uno: editorial / podcast / comunidad / boletín.

Escribe en /tmp/cprf-pr-patterns.json:

python3 << 'PYEOF'
import json

patterns = {
    "tier_1_channels": [
        # COMPLETA: canales que aparecen en 3+ competidores
        # Cada uno: {"channel_name": str, "channel_url": str, "channel_type": str,
        #        "frequency": int, "found_in_competitors": [str],
        #        "evidence_urls": [str], "story_angles_used": [str],
        #        "journalist_name": "", "journalist_beat": ""}
    ],
    "tier_2_channels": [
        # COMPLETA: canales que aparecen en exactamente 2 competidores
        # Cada uno: {"channel_name": str, "channel_url": str, "channel_type": str,
        #        "frequency": int, "found_in_competitors": [str],
        #        "evidence_urls": [str], "story_angles_used": [str],
        #        "journalist_name": "", "journalist_beat": ""}
    ],
    "tier_3_channels": [
        # COMPLETA: canales que aparecen en 1 competidor
        # Cada uno: {"channel_name": str, "channel_url": str, "channel_type": str,
        #        "frequency": int, "found_in_competitors": [str],
        #        "evidence_urls": [str], "story_angles_used": [str],
        #        "journalist_name": "", "journalist_beat": ""}
    ],
    "data_quality_flags": []
}

json.dump(patterns, open('/tmp/cprf-pr-patterns.json', 'w'), indent=2)
print('Análisis de patrones de PR escrito.')
PYEOF

Paso 8: Investigación de Periodistas y Anfitriones

Para canales de Nivel 1 y Nivel 2 solo. Omite el Nivel 3: no vale la pena el esfuerzo de divulgación.

Busca al periodista o anfitrión específico que cubre tu nicho para cada canal de nivel 1 y 2:

python3 scripts/research.py \
  --phase journalist \
  --patterns /tmp/cprf-pr-patterns.json \
  --product-analysis /tmp/cprf-product-analysis.json \
  --tavily-key "$TAVILY_API_KEY" \
  --output /tmp/cprf-journalists-raw.json

Imprime los resultados de la investigación de periodistas:

python3 -c "
import json
data = json.load(open('/tmp/cprf-journalists-raw.json'))
print(f'Canales investigados: {len(data[\"channels_researched\"])}')
for channel, result in data['results'].items():
    print(f'\n=== {channel} ===')
    print(f'Búsqueda: {result[\"search_query\"]}')
    print(f'Respuesta: {result.get(\"answer\",\"\")[:300]}')
"

Instrucciones para la IA: Lee los resultados de la investigación de periodistas. Para cada canal de nivel 1 y 2, extrae el periodista o anfitrión más relevante que escriba sobre tu nicho de producto (L3). Proporciona:

  • journalist_name: nombre completo del periodista/anfitrión
  • journalist_email (opcional, si se encuentra en uno de los primeros 3 resultados)
  • journalist_beat: qué cubren (ej., "Startups SaaS", "Herramientas DevOps", "Fundadores de Fintech")
  • source_url: la URL de los resultados de búsqueda donde se encontró esta información
  • evidence_snippet: una cita textual del fragmento de búsqueda que mencione al periodista

Si no se encuentra un periodista/anfitrión para un canal: Establece journalist_name como "No encontrado" y escribe un finding_note que explique por qué (ej., "Este canal de YouTube no muestra nombres de anfitriones en sus páginas de episodios"). No inventes un nombre.

Actualiza el archivo de patrones:

python3 << 'PYEOF'
import json

patterns = json.load(open('/tmp/cprf-pr-patterns.json'))
journalist_data = json.load(open('/tmp/cprf-journalists-raw.json'))

for channel_entry in patterns['tier_1_channels'] + patterns['tier_2_channels']:
    channel_key = channel_entry['channel_url']
    if channel_key in journalist_data['results']:
        j_result = journalist_data['results'][channel_key]
        channel_entry['journalist_name'] = j_result.get('journalist_name', '')
        channel_entry['journalist_email'] = j_result.get('journalist_email', '')
        channel_entry['journalist_beat'] = j_result.get('journalist_beat', '')
        channel_entry['journalist_source_url'] = j_result.get('source_url', '')

json.dump(patterns, open('/tmp/cprf-pr-patterns.json', 'w'), indent=2)
print('Archivo de patrones actualizado con datos de periodistas.')
PYEOF

Paso 9: Crear la Lista de Contactos de Divulgación

Lee el archivo de clasificación de niveles para verificar las reglas:

cat references/tier-scoring.md

Construye una tabla de canales agrupada por nivel:

python3 << 'PYEOF'
import json

patterns = json.load(open('/tmp/cprf-pr-patterns.json'))

print('\n===== LISTA DE CONTACTOS DE PR =====')
print()

for tier_key, tier_label in [('tier_1_channels', 'NIVEL 1: CANALES PROBADOS (3+ competidores)'),
                              ('tier_2_channels', 'NIVEL 2: CANALES EMERGENTES (2 competidores)'),
                              ('tier_3_channels', 'NIVEL 3: CANALES DE OPORTUNIDAD (1 competidor)')]:
    channels = patterns[tier_key]
    if not channels:
        continue
    print(f'\n## {tier_label}')
    print()
    print(f'| Canal | URL | Tipo | Frecuencia | Periodista | Ángulo de Historia |')
    print(f'|---|---|---|---|---|---|')
    for ch in channels:
        j_name = ch.get('journalist_name', 'No encontrado') or 'No encontrado'
        angle = ch.get('story_angles_used', ['General'])[0]
        print(f'| {ch["channel_name"]} | {ch["channel_url"]} | {ch["channel_type"]} | {ch["frequency"]} | {j_name} | {angle} |')

json.dump(patterns, open('/tmp/cprf-pr-patterns.json', 'w'), indent=2)
PYEOF

Paso 10: Redactar Propuestas Frías (IA)

Lee la guía de propuestas:

cat references/pitch-guide.md

Instrucciones para la IA: Redacta exactamente 1 propuesta fría para cada canal de Nivel 1. (Nivel 2 y 3 se pueden omitir o crear bajo demanda.)

Cada propuesta debe incluir:

  • journalist_name: el nombre del periodista/anfitrión
  • outlet: el nombre del canal/publicación
  • story_angle: el ángulo de historia extraído de la evidencia de PR del competidor
  • product_angle: cómo se relaciona el diferenciador del producto con ese ángulo (basado en el análisis del producto)
  • pitch_type: newswire / story-pitch / podcast-pitch / community-post / comparison-article
  • pitch_body: el borrador completo de la propuesta, escrito en el tono adecuado para el canal. No uses comillas de ningún tipo en el pitch_body; usa comillas angulares (« »).

Ejemplo de salida de propuesta:

{
  "pitch": {
    "target": "Sarah Perez",
    "outlet": "TechCrunch",
    "subject": "Automatización de CI/CD autogestionada: cómo [Producto] está resolviendo el problema de seguridad de datos que las soluciones en la nube pasan por alto",
    "story_angle": "Artículo de tendencia sobre por qué los equipos de DevOps están volviendo a soluciones autogestionadas",
    "product_angle": "Diferenciador de autogestionado + seguridad de datos",
    "pitch_type": "story-pitch",
    "pitch_body": "Hola Sarah, vi tu reciente artículo sobre DevOps autogestionado en TechCrunch. En [Producto], creemos que la seguridad de datos no debería ser un compromiso al escalar pipelines de CI/CD. Nuestro ejecutor autogestionado garantiza que ningún dato salga de la infraestructura del cliente, mientras ofrece funciones como soporte nativo para monorepos que faltan en soluciones en la nube. Creo que a tus lectores les encantaría una inmersión en cómo estamos abordando esta brecha. ¿Te interesaría una demo o una entrevista con nuestro CTO?"
  }
}

Validación: Verifica cada propuesta contra estas reglas:

  1. ¿El ángulo de historia se traza a un título de artículo/episodio específico en los resultados de búsqueda?
  2. ¿El ángulo del producto se traza a una línea específica del análisis del producto?
  3. ¿Se menciona al periodista/anfitrión correcto?
  4. ¿La propuesta evita el lenguaje genérico de relaciones públicas?
  5. ¿El pitch_body tiene menos de 150 palabras?
  6. ¿La línea de asunto tiene menos de 15 palabras?

Después de la redacción, consolida en el archivo de salida final:

python3 << 'PYEOF'
import json

patterns = json.load(open('/tmp/cprf-pr-patterns.json'))
product = json.load(open('/tmp/cprf-product-analysis.json'))

output = {
    "product": product['product_name'],
    "industry": product['industry_taxonomy'],
    "generated_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
    "outreach_list": patterns,
    "pitches": [
        # COMPLETA: 1 propuesta por canal de nivel 1
    ],
    "next_steps": [
        "Revisa cada propuesta en busca de personalización antes de enviar.",
        "Verifica la información de contacto del periodista en LinkedIn o Twitter.",
        "Da seguimiento después de 7 días si no hay respuesta.",
        "Los canales de Nivel 2 y Nivel 3 se pueden abordar más adelante."
    ]
}

json.dump(output, open('/tmp/cprf-final-output.json', 'w'), indent=2)
print(f'Resultado final escrito: {len(output["pitches"])} propuestas para {len(output["outreach_list"]["tier_1_channels"])} canales de nivel 1.')
PYEOF

Entrega al Usuario

Lee de /tmp/cprf-final-output.json y muéstrale al usuario:

  1. Resumen de tu producto (nombre, industria, diferenciadores)
  2. Lista de contactos -- tabla con canales agrupados por nivel (Nivel 1, 2, 3)
  3. Propuestas listas para enviar -- propuesta completa para cada canal de Nivel 1
  4. Próximos pasos

Formato de entrega: Usa formato de tabla para la lista de contactos y bloques de cita o código para las propuestas. Mantén el JSON crudo como archivo adjunto disponible si se solicita.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

Varnan-Tech/opendirectory

Use when the user asks to generate a blog cover image, thumbnail, or article header. Automatically uses modern typography, brand logos, and Google Search grounding to create beautiful 16:9 images with Gemini 3.1 Flash Image Preview.

Varnan-Tech/opendirectory

World-class brand strategist and naming expert. Uses an interrogation-led discovery phase to extract your brand's DNA, then applies scientific naming frameworks (Phonosemantics) and automated multi-TLD domain checking.

Varnan-Tech/opendirectory

Use when the user asks to generate or update a project's CLAUDE or AGENTS context file from a codebase scan. Writes a focused file under 100 lines containing only the non-obvious build commands, conventions, and gotchas Claude Code needs.

Varnan-Tech/opendirectory

Use when the user wants to verify cold emails, enrich a lead list, or autonomously guess email addresses from a CSV using ValidEmail.co or the open-source Reacher engine.

Varnan-Tech/opendirectory

Competitive intelligence orchestrator tracking companies across 8+ platforms (GitHub, Twitter, Reddit, HN, PH, YC Jobs) with heat scores and AI briefings.

Varnan-Tech/opendirectory

Generate high-converting, deep-dive growth case studies in MDX format. Use this skill when asked to write a case study or blog post about a company's growth, tech stack, or product-led strategy. It handles the full pipeline (researching the company via Tavily, generating a 16:9 cover image, quality checking the draft, uploading assets to cloud storage, and pushing directly to the target repository).

Varnan-Tech/opendirectory

Scans your project for outdated npm, pip, Cargo, Go, or Ruby packages. Runs a CVE security audit. Fetches changelogs, summarizes breaking changes with Gemini, and opens one PR per risk group (patch, minor, major). Includes Diagnosis Mode for install conflicts. Use when asked to update dependencies, check for outdated packages, open dependency PRs, scan for package updates, audit for CVEs, or flag breaking changes in upgrades. Trigger when a user says "check for outdated packages", "update my dependencies", "open PRs for dependency updates", "scan for CVEs", or "which packages need upgrading".

Varnan-Tech/opendirectory

Generates and updates README.md and API reference docs by reading your codebase's functions, routes, types, schemas, and architecture. Uses graphify to build a knowledge graph first, then writes accurate docs from it. Use when asked to write docs, generate a README, document an API, update stale docs, create an API reference from code, add an architecture section, or document a project in any language. Trigger when a user says their docs are missing, outdated, or wants to document their codebase without writing it manually.

Varnan-Tech/opendirectory

Evaluates expired domain candidates against a target niche, scores them by topical relevance, historical activity level, and history cleanliness, then outputs a ranked shortlist with explainable reasoning and risk flags.

Varnan-Tech/opendirectory

Brutally honest developer-experience audit for a GitHub repo. Scores 10 DX dimensions (time-to-first-success, README clarity, visual proof, install, quick-start, docs, examples, community, trust, marketing), writes a shareable roast in the requested tone (brutal/honest/kind), produces a prioritized action plan ranked by impact × effort, and sketches an ideal README. Trigger when user says "roast my repo", "audit my README", "dx audit", "developer experience review", "score my GitHub project", "before launch checklist", or "make my repo shareable".

Varnan-Tech/opendirectory

Drafts and designs a complete HTML email newsletter from a topic or content brief. Outputs paste-ready HTML for Loops, Mailchimp, Beehiiv, Resend, or any standard email platform. Includes subject line options and plain-text fallback. Trigger when a user says "write a newsletter", "draft an email newsletter", "create an HTML email", "design an email for my subscribers", or "write a newsletter about [topic]".

Varnan-Tech/opendirectory

Takes a GitHub PR URL or the current branch and writes a plain-English explanation of what it does and why, then posts it as a PR comment. Use when asked to explain a PR, summarize a pull request, write a plain-English description of a PR, add a summary comment to a PR, or understand what a PR changes. Trigger when a user says "explain this PR", "summarize this pull request", "what does this PR do", "add a comment explaining the PR", or shares a GitHub PR URL and asks what it does.

Varnan-Tech/opendirectory

Audit how often LLMs recommend your brand vs competitors and generate a GEO action plan.

Varnan-Tech/opendirectory

Takes a competitor's public GitHub repo URL, fetches their open issues via the GitHub REST API, filters noise locally, clusters issues into 6 demand categories, computes a demand score per issue and per cluster, and outputs a ranked demand gap report with a GTM messaging brief. Use when asked to scan a competitor's GitHub issues, find what their users are begging for, turn GitHub complaints into product positioning, identify competitor feature gaps, or generate messaging from real user demand. Trigger when a user says "scan competitor issues", "what are users asking for on X repo", "find demand gaps in Y", "turn GitHub issues into messaging", or "what should I build based on competitor complaints".

Varnan-Tech/opendirectory

Find recurring confusion in your repo's GitHub Discussions, rank it by urgency, and draft the actual docs fixes and content angles — with verbatim community quotes and source links as evidence.

Varnan-Tech/opendirectory

SEO keyword research workflow for blog generation using Google Trends data. Use when writing blog posts, planning content calendars, or optimizing articles for search engines. Finds breakout keywords, builds content structure, and generates SEO-optimized blog outlines targeting tech and developer audiences.

Varnan-Tech/opendirectory

Generates a professionally designed case study PDF for B2B SaaS sales and marketing. Supports 7 page layouts, 9 style presets, 1-4 page output. Trigger when user says "create a case study", "write a customer story", "make a case study PDF", "design a success story", "turn this customer win into a PDF".

Varnan-Tech/opendirectory

Generates data visualization charts (bar, line, area, pie, doughnut, scatter, radar, treemap) as PNG using Apache ECharts v6. 1080×1080px default, 5 style presets, highlight annotations. Trigger when user says "create a chart", "visualize data", "make a bar chart", "line graph", "pie chart", "data visualization", "chart this data", "plot", "graph", or "visualize these numbers".

Varnan-Tech/opendirectory

Creates professionally designed B2B SaaS e-books in HTML + CSS, exported as print-ready PDF. 3–10 pages, 9 style presets, 11 page layout types. Trigger when user says "create an ebook", "design a lead magnet", "make a PDF guide", "build a gated content piece", "write a B2B ebook", "design a white paper", "create a nurture asset", or "make a PDF report".

Varnan-Tech/opendirectory

Fetches low-star App Store and Google Play reviews, clusters them into broken-promise patterns, and generates a ranked copy brief with positioning opportunities.

Skills relacionados