Modo: scan — Portal Scanner (Descubrimiento de Ofertas)
Modo: scan — Portal Scanner (Descubrimiento de Ofertas)
Escanea portales de empleo configurados, filtra por relevancia de título, y añade nuevas ofertas al pipeline para evaluación posterior.
Ejecución recomendada
Ejecutar como subagente para no consumir contexto del main:
Agent(
subagent_type="general-purpose",
prompt="[contenido de este archivo + datos específicos]",
run_in_background=True
)
Configuración
Leer portals.yml que contiene:
search_queries: Lista de queries WebSearch consite:filters por portal (descubrimiento amplio)tracked_companies: Empresas específicas concareers_urlpara navegación directatitle_filter: Keywords positive/negative/seniority_boost para filtrado de títulos
Estrategia de descubrimiento (3 niveles)
Nivel 1 — Playwright directo (PRINCIPAL)
Para cada empresa en tracked_companies: Navegar a su careers_url con Playwright (browser_navigate + browser_snapshot), leer TODOS los job listings visibles, y extraer título + URL de cada uno. Este es el método más fiable porque:
- Ve la página en tiempo real (no resultados cacheados de Google)
- Funciona con SPAs (Ashby, Lever, Workday)
- Detecta ofertas nuevas al instante
- No depende de la indexación de Google
Cada empresa DEBE tener careers_url en portals.yml. Si no la tiene, buscarla una vez, guardarla, y usar en futuros scans.
Nivel 2 — Greenhouse API (COMPLEMENTARIO)
Para empresas con Greenhouse, la API JSON (boards-api.greenhouse.io/v1/boards/{slug}/jobs) devuelve datos estructurados limpios. Usar como complemento rápido de Nivel 1 — es más rápido que Playwright pero solo funciona con Greenhouse.
Nivel 3 — WebSearch queries (DESCUBRIMIENTO AMPLIO)
Los search_queries con site: filters cubren portales de forma transversal (todos los Ashby, todos los Greenhouse, etc.). Útil para descubrir empresas NUEVAS que aún no están en tracked_companies, pero los resultados pueden estar desfasados.
Prioridad de ejecución:
- Nivel 1: Playwright → todas las
tracked_companiesconcareers_url - Nivel 2: API → todas las
tracked_companiesconapi: - Nivel 3: WebSearch → todos los
search_queriesconenabled: true
Los niveles son aditivos — se ejecutan todos, los resultados se mezclan y deduplicar.
Workflow
- Leer configuración:
portals.yml - Leer historial:
data/scan-history.tsv→ URLs ya vistas Leer dedup sources:
data/applications.md+data/pipeline.mdNivel 1 — Playwright scan (paralelo en batches de 3-5): Para cada empresa en
tracked_companiesconenabled: trueycareers_urldefinida: a.browser_navigatea lacareers_urlb.browser_snapshotpara leer todos los job listings c. Si la página tiene filtros/departamentos, navegar las secciones relevantes d. Para cada job listing extraer:{title, url, company}e. Si la página pagina resultados, navegar páginas adicionales f. Acumular en lista de candidatos g. Sicareers_urlfalla (404, redirect), intentarscan_querycomo fallback y anotar para actualizar la URLNivel 2 — Greenhouse APIs (paralelo): Para cada empresa en
tracked_companiesconapi:definida yenabled: true: a. WebFetch de la URL de API → JSON con lista de jobs b. Para cada job extraer:{title, url, company}c. Acumular en lista de candidatos (dedup con Nivel 1)- Nivel 3 — WebSearch queries (paralelo si posible): Para cada query en
search_queriesconenabled: true: a. Ejecutar WebSearch con elquerydefinido b. De cada resultado extraer:{title, url, company}title: del título del resultado (antes del “ @ “ o “ ”) - url: URL del resultado
- company: después del “ @ “ en el título, o extraer del dominio/path c. Acumular en lista de candidatos (dedup con Nivel 1+2)
- Filtrar por título usando
title_filterdeportals.yml:- Al menos 1 keyword de
positivedebe aparecer en el título (case-insensitive) - 0 keywords de
negativedeben aparecer seniority_boostkeywords dan prioridad pero no son obligatorios
- Al menos 1 keyword de
- Deduplicar contra 3 fuentes:
scan-history.tsv→ URL exacta ya vistaapplications.md→ empresa + rol normalizado ya evaluadopipeline.md→ URL exacta ya en pendientes o procesadas
Para cada oferta nueva que pase filtros: a. Añadir a
pipeline.mdsección “Pendientes”:- [ ] {url} | {company} | {title}b. Registrar enscan-history.tsv:{url}\t{date}\t{query_name}\t{title}\t{company}\tadded- Ofertas filtradas por título: registrar en
scan-history.tsvcon statusskipped_title - Ofertas duplicadas: registrar con status
skipped_dup
Extracción de título y empresa de WebSearch results
Los resultados de WebSearch vienen en formato: "Job Title @ Company" o "Job Title | Company" o "Job Title — Company".
Patrones de extracción por portal:
- Ashby:
"Senior AI PM (Remote) @ EverAI"→ title:Senior AI PM, company:EverAI - Greenhouse:
"AI Engineer at Anthropic"→ title:AI Engineer, company:Anthropic - Lever:
"Product Manager - AI @ Temporal"→ title:Product Manager - AI, company:Temporal
Regex genérico: (.+?)(?:\s*[@|—–-]\s*|\s+at\s+)(.+?)$
URLs privadas
Si se encuentra una URL no accesible públicamente:
- Guardar el JD en
jds/{company}-{role-slug}.md - Añadir a pipeline.md como:
- [ ] local:jds/{company}-{role-slug}.md | {company} | {title}
Scan History
data/scan-history.tsv trackea TODAS las URLs vistas:
url first_seen portal title company status
https://... 2026-02-10 Ashby — AI PM PM AI Acme added
https://... 2026-02-10 Greenhouse — SA Junior Dev BigCo skipped_title
https://... 2026-02-10 Ashby — AI PM SA AI OldCo skipped_dup
Resumen de salida
Portal Scan — {YYYY-MM-DD}
━━━━━━━━━━━━━━━━━━━━━━━━━━
Queries ejecutados: N
Ofertas encontradas: N total
Filtradas por título: N relevantes
Duplicadas: N (ya evaluadas o en pipeline)
Nuevas añadidas a pipeline.md: N
+ {company} | {title} | {query_name}
...
→ Ejecuta /career-ops pipeline para evaluar las nuevas ofertas.
Gestión de careers_url
Cada empresa en tracked_companies debe tener careers_url — la URL directa a su página de ofertas. Esto evita buscarlo cada vez.
Patrones conocidos por plataforma:
- Ashby:
https://jobs.ashbyhq.com/{slug} - Greenhouse:
https://job-boards.greenhouse.io/{slug}ohttps://job-boards.eu.greenhouse.io/{slug} - Lever:
https://jobs.lever.co/{slug} - Custom: La URL propia de la empresa (ej:
https://openai.com/careers)
Si careers_url no existe para una empresa:
- Intentar el patrón de su plataforma conocida
- Si falla, hacer un WebSearch rápido:
"{company}" careers jobs - Navegar con Playwright para confirmar que funciona
- Guardar la URL encontrada en portals.yml para futuros scans
Si careers_url devuelve 404 o redirect:
- Anotar en el resumen de salida
- Intentar scan_query como fallback
- Marcar para actualización manual
Mantenimiento del portals.yml
- SIEMPRE guardar
careers_urlcuando se añade una empresa nueva - Añadir nuevos queries según se descubran portales o roles interesantes
- Desactivar queries con
enabled: falsesi generan demasiado ruido - Ajustar keywords de filtrado según evolucionen los roles target
- Añadir empresas a
tracked_companiescuando interese seguirlas de cerca - Verificar
careers_urlperiódicamente — las empresas cambian de plataforma ATS
