initial public release
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
# System Context -- career-ops
|
||||
|
||||
<!-- ============================================================
|
||||
THIS FILE IS AUTO-UPDATABLE. Don't put personal data here.
|
||||
|
||||
Your customizations go in modes/_profile.md (never auto-updated).
|
||||
This file contains system rules, scoring logic, and tool config
|
||||
that improve with each career-ops release.
|
||||
============================================================ -->
|
||||
|
||||
## Sources of Truth
|
||||
|
||||
| File | Path | When |
|
||||
|------|------|------|
|
||||
| cv.md | `cv.md` (project root) | ALWAYS |
|
||||
| article-digest.md | `article-digest.md` (if exists) | ALWAYS (detailed proof points) |
|
||||
| profile.yml | `config/profile.yml` | ALWAYS (candidate identity and targets) |
|
||||
| _profile.md | `modes/_profile.md` | ALWAYS (user archetypes, narrative, negotiation) |
|
||||
|
||||
**RULE: NEVER hardcode metrics from proof points.** Read them from cv.md + article-digest.md at evaluation time.
|
||||
**RULE: For article/project metrics, article-digest.md takes precedence over cv.md.**
|
||||
**RULE: Read _profile.md AFTER this file. User customizations in _profile.md override defaults here.**
|
||||
|
||||
---
|
||||
|
||||
## Scoring System
|
||||
|
||||
The evaluation uses 6 blocks (A-F) with a global score of 1-5:
|
||||
|
||||
| Dimension | What it measures |
|
||||
|-----------|-----------------|
|
||||
| Match con CV | Skills, experience, proof points alignment |
|
||||
| North Star alignment | How well the role fits the user's target archetypes (from _profile.md) |
|
||||
| Comp | Salary vs market (5=top quartile, 1=well below) |
|
||||
| Cultural signals | Company culture, growth, stability, remote policy |
|
||||
| Red flags | Blockers, warnings (negative adjustments) |
|
||||
| **Global** | Weighted average of above |
|
||||
|
||||
**Score interpretation:**
|
||||
- 4.5+ → Strong match, recommend applying immediately
|
||||
- 4.0-4.4 → Good match, worth applying
|
||||
- 3.5-3.9 → Decent but not ideal, apply only if specific reason
|
||||
- Below 3.5 → Recommend against applying (see Ethical Use in CLAUDE.md)
|
||||
|
||||
## Posting Legitimacy (Block G)
|
||||
|
||||
Block G assesses whether a posting is likely a real, active opening. It does NOT affect the 1-5 global score -- it is a separate qualitative assessment.
|
||||
|
||||
**Three tiers:**
|
||||
- **High Confidence** -- Real, active opening (most signals positive)
|
||||
- **Proceed with Caution** -- Mixed signals, worth noting (some concerns)
|
||||
- **Suspicious** -- Multiple ghost indicators, user should investigate first
|
||||
|
||||
**Key signals (weighted by reliability):**
|
||||
|
||||
| Signal | Source | Reliability | Notes |
|
||||
|--------|--------|-------------|-------|
|
||||
| Posting age | Page snapshot | High | Under 30d=good, 30-60d=mixed, 60d+=concerning (adjusted for role type) |
|
||||
| Apply button active | Page snapshot | High | Direct observable fact |
|
||||
| Tech specificity in JD | JD text | Medium | Generic JDs correlate with ghost postings but also with poor writing |
|
||||
| Requirements realism | JD text | Medium | Contradictions are a strong signal, vagueness is weaker |
|
||||
| Recent layoff news | WebSearch | Medium | Must consider department, timing, and company size |
|
||||
| Reposting pattern | scan-history.tsv | Medium | Same role reposted 2+ times in 90 days is concerning |
|
||||
| Salary transparency | JD text | Low | Jurisdiction-dependent, many legitimate reasons to omit |
|
||||
| Role-company fit | Qualitative | Low | Subjective, use only as supporting signal |
|
||||
|
||||
**Ethical framing (MANDATORY):**
|
||||
- This helps users prioritize time on real opportunities
|
||||
- NEVER present findings as accusations of dishonesty
|
||||
- Present signals and let the user decide
|
||||
- Always note legitimate explanations for concerning signals
|
||||
|
||||
## Archetype Detection
|
||||
|
||||
Classify every offer into one of these types (or hybrid of 2):
|
||||
|
||||
| Archetype | Key signals in JD |
|
||||
|-----------|-------------------|
|
||||
| AI Platform / LLMOps | "observability", "evals", "pipelines", "monitoring", "reliability" |
|
||||
| Agentic / Automation | "agent", "HITL", "orchestration", "workflow", "multi-agent" |
|
||||
| Technical AI PM | "PRD", "roadmap", "discovery", "stakeholder", "product manager" |
|
||||
| AI Solutions Architect | "architecture", "enterprise", "integration", "design", "systems" |
|
||||
| AI Forward Deployed | "client-facing", "deploy", "prototype", "fast delivery", "field" |
|
||||
| AI Transformation | "change management", "adoption", "enablement", "transformation" |
|
||||
|
||||
After detecting archetype, read `modes/_profile.md` for the user's specific framing and proof points for that archetype.
|
||||
|
||||
## Global Rules
|
||||
|
||||
### NEVER
|
||||
|
||||
1. Invent experience or metrics
|
||||
2. Modify cv.md or portfolio files
|
||||
3. Submit applications on behalf of the candidate
|
||||
4. Share phone number in generated messages
|
||||
5. Recommend comp below market rate
|
||||
6. Generate a PDF without reading the JD first
|
||||
7. Use corporate-speak
|
||||
8. Ignore the tracker (every evaluated offer gets registered)
|
||||
|
||||
### ALWAYS
|
||||
|
||||
0. **Cover letter:** If the form allows it, ALWAYS include one. Same visual design as CV. JD quotes mapped to proof points. 1 page max.
|
||||
1. Read cv.md, _profile.md, and article-digest.md (if exists) before evaluating
|
||||
1b. **First evaluation of each session:** Run `node cv-sync-check.mjs`. If warnings, notify user.
|
||||
2. Detect the role archetype and adapt framing per _profile.md
|
||||
3. Cite exact lines from CV when matching
|
||||
4. Use WebSearch for comp and company data
|
||||
5. Register in tracker after evaluating
|
||||
6. Generate content in the language of the JD (EN default)
|
||||
7. Be direct and actionable -- no fluff
|
||||
8. Native tech English for generated text. Short sentences, action verbs, no passive voice.
|
||||
8b. Case study URLs in PDF Professional Summary (recruiter may only read this).
|
||||
9. **Tracker additions as TSV** -- NEVER edit applications.md directly. Write TSV in `batch/tracker-additions/`.
|
||||
10. **Include `**URL:**` in every report header.**
|
||||
|
||||
### Tools
|
||||
|
||||
| Tool | Use |
|
||||
|------|-----|
|
||||
| WebSearch | Comp research, trends, company culture, LinkedIn contacts, fallback for JDs |
|
||||
| WebFetch | Fallback for extracting JDs from static pages |
|
||||
| Playwright | Verify offers (browser_navigate + browser_snapshot). **NEVER 2+ agents with Playwright in parallel.** |
|
||||
| Read | cv.md, _profile.md, article-digest.md, cv-template.html |
|
||||
| Write | Temporary HTML for PDF, applications.md, reports .md |
|
||||
| Edit | Update tracker |
|
||||
| Canva MCP | Optional visual CV generation. Duplicate base design, edit text, export PDF. Requires `canva_resume_design_id` in profile.yml. |
|
||||
| Bash | `node generate-pdf.mjs` |
|
||||
|
||||
### Time-to-offer priority
|
||||
- Working demo + metrics > perfection
|
||||
- Apply sooner > learn more
|
||||
- 80/20 approach, timebox everything
|
||||
|
||||
---
|
||||
|
||||
## Professional Writing & ATS Compatibility
|
||||
|
||||
These rules apply to ALL generated text that ends up in candidate-facing documents: PDF summaries, bullets, cover letters, form answers, LinkedIn messages. They do NOT apply to internal evaluation reports.
|
||||
|
||||
### Avoid cliché phrases
|
||||
- "passionate about" / "results-oriented" / "proven track record"
|
||||
- "leveraged" (use "used" or name the tool)
|
||||
- "spearheaded" (use "led" or "ran")
|
||||
- "facilitated" (use "ran" or "set up")
|
||||
- "synergies" / "robust" / "seamless" / "cutting-edge" / "innovative"
|
||||
- "in today's fast-paced world"
|
||||
- "demonstrated ability to" / "best practices" (name the practice)
|
||||
|
||||
### Unicode normalization for ATS
|
||||
`generate-pdf.mjs` automatically normalizes em-dashes, smart quotes, and zero-width characters to ASCII equivalents for maximum ATS compatibility. But avoid generating them in the first place.
|
||||
|
||||
### Vary sentence structure
|
||||
- Don't start every bullet with the same verb
|
||||
- Mix sentence lengths (short. Then longer with context. Short again.)
|
||||
- Don't always use "X, Y, and Z" — sometimes two items, sometimes four
|
||||
|
||||
### Prefer specifics over abstractions
|
||||
- "Cut p95 latency from 2.1s to 380ms" beats "improved performance"
|
||||
- "Postgres + pgvector for retrieval over 12k docs" beats "designed scalable RAG architecture"
|
||||
- Name tools, projects, and customers when allowed
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
# Modo: oferta — Evaluación Completa A-G
|
||||
|
||||
Cuando el candidato pega una oferta (texto o URL), entregar SIEMPRE los 7 bloques (A-F evaluation + G legitimacy):
|
||||
|
||||
## Paso 0 — Detección de Arquetipo
|
||||
|
||||
Clasificar la oferta en uno de los 6 arquetipos (ver `_shared.md`). Si es híbrido, indicar los 2 más cercanos. Esto determina:
|
||||
- Qué proof points priorizar en bloque B
|
||||
- Cómo reescribir el summary en bloque E
|
||||
- Qué historias STAR preparar en bloque F
|
||||
|
||||
## Bloque A — Resumen del Rol
|
||||
|
||||
Tabla con:
|
||||
- Arquetipo detectado
|
||||
- Domain (platform/agentic/LLMOps/ML/enterprise)
|
||||
- Function (build/consult/manage/deploy)
|
||||
- Seniority
|
||||
- Remote (full/hybrid/onsite)
|
||||
- Team size (si se menciona)
|
||||
- TL;DR en 1 frase
|
||||
|
||||
## Bloque B — Match con CV
|
||||
|
||||
Lee `cv.md`. Crea tabla con cada requisito del JD mapeado a líneas exactas del CV.
|
||||
|
||||
**Adaptado al arquetipo:**
|
||||
- Si FDE → priorizar proof points de delivery rápida y client-facing
|
||||
- Si SA → priorizar diseño de sistemas e integrations
|
||||
- Si PM → priorizar product discovery y métricas
|
||||
- Si LLMOps → priorizar evals, observability, pipelines
|
||||
- Si Agentic → priorizar multi-agent, HITL, orchestration
|
||||
- Si Transformation → priorizar change management, adoption, scaling
|
||||
|
||||
Sección de **gaps** con estrategia de mitigación para cada uno. Para cada gap:
|
||||
1. ¿Es un hard blocker o un nice-to-have?
|
||||
2. ¿Puede el candidato demostrar experiencia adyacente?
|
||||
3. ¿Hay un proyecto portfolio que cubra este gap?
|
||||
4. Plan de mitigación concreto (frase para cover letter, proyecto rápido, etc.)
|
||||
|
||||
## Bloque C — Nivel y Estrategia
|
||||
|
||||
1. **Nivel detectado** en el JD vs **nivel natural del candidato para ese arquetipo**
|
||||
2. **Plan "vender senior sin mentir"**: frases específicas adaptadas al arquetipo, logros concretos a destacar, cómo posicionar la experiencia de founder como ventaja
|
||||
3. **Plan "si me downlevelan"**: aceptar si comp es justa, negociar review a 6 meses, criterios de promoción claros
|
||||
|
||||
## Bloque D — Comp y Demanda
|
||||
|
||||
Usar WebSearch para:
|
||||
- Salarios actuales del rol (Glassdoor, Levels.fyi, Blind)
|
||||
- Reputación de compensación de la empresa
|
||||
- Tendencia de demanda del rol
|
||||
|
||||
Tabla con datos y fuentes citadas. Si no hay datos, decirlo en vez de inventar.
|
||||
|
||||
## Bloque E — Plan de Personalización
|
||||
|
||||
| # | Sección | Estado actual | Cambio propuesto | Por qué |
|
||||
|---|---------|---------------|------------------|---------|
|
||||
| 1 | Summary | ... | ... | ... |
|
||||
| ... | ... | ... | ... | ... |
|
||||
|
||||
Top 5 cambios al CV + Top 5 cambios a LinkedIn para maximizar match.
|
||||
|
||||
## Bloque F — Plan de Entrevistas
|
||||
|
||||
6-10 historias STAR+R mapeadas a requisitos del JD (STAR + **Reflection**):
|
||||
|
||||
| # | Requisito del JD | Historia STAR+R | S | T | A | R | Reflection |
|
||||
|---|-----------------|-----------------|---|---|---|---|------------|
|
||||
|
||||
The **Reflection** column captures what was learned or what would be done differently. This signals seniority — junior candidates describe what happened, senior candidates extract lessons.
|
||||
|
||||
**Story Bank:** If `interview-prep/story-bank.md` exists, check if any of these stories are already there. If not, append new ones. Over time this builds a reusable bank of 5-10 master stories that can be adapted to any interview question.
|
||||
|
||||
**Seleccionadas y enmarcadas según el arquetipo:**
|
||||
- FDE → enfatizar velocidad de entrega y client-facing
|
||||
- SA → enfatizar decisiones de arquitectura
|
||||
- PM → enfatizar discovery y trade-offs
|
||||
- LLMOps → enfatizar métricas, evals, production hardening
|
||||
- Agentic → enfatizar orchestration, error handling, HITL
|
||||
- Transformation → enfatizar adopción, cambio organizacional
|
||||
|
||||
Incluir también:
|
||||
- 1 case study recomendado (cuál de sus proyectos presentar y cómo)
|
||||
- Preguntas red-flag y cómo responderlas (ej: "¿por qué vendiste tu empresa?", "¿tienes equipo de reports?")
|
||||
|
||||
## Bloque G — Posting Legitimacy
|
||||
|
||||
Analyze the job posting for signals that indicate whether this is a real, active opening. This helps the user prioritize their effort on opportunities most likely to result in a hiring process.
|
||||
|
||||
**Ethical framing:** Present observations, not accusations. Every signal has legitimate explanations. The user decides how to weigh them.
|
||||
|
||||
### Signals to analyze (in order):
|
||||
|
||||
**1. Posting Freshness** (from Playwright snapshot, already captured in Paso 0):
|
||||
- Date posted or "X days ago" -- extract from page
|
||||
- Apply button state (active / closed / missing / redirects to generic page)
|
||||
- If URL redirected to generic careers page, note it
|
||||
|
||||
**2. Description Quality** (from JD text):
|
||||
- Does it name specific technologies, frameworks, tools?
|
||||
- Does it mention team size, reporting structure, or org context?
|
||||
- Are requirements realistic? (years of experience vs technology age)
|
||||
- Is there a clear scope for the first 6-12 months?
|
||||
- Is salary/compensation mentioned?
|
||||
- What ratio of the JD is role-specific vs generic boilerplate?
|
||||
- Any internal contradictions? (entry-level title + staff requirements, etc.)
|
||||
|
||||
**3. Company Hiring Signals** (2-3 WebSearch queries, combine with Block D research):
|
||||
- Search: `"{company}" layoffs {year}` -- note date, scale, departments
|
||||
- Search: `"{company}" hiring freeze {year}` -- note any announcements
|
||||
- If layoffs found: are they in the same department as this role?
|
||||
|
||||
**4. Reposting Detection** (from scan-history.tsv):
|
||||
- Check if company + similar role title appeared before with a different URL
|
||||
- Note how many times and over what period
|
||||
|
||||
**5. Role Market Context** (qualitative, no additional queries):
|
||||
- Is this a common role that typically fills in 4-6 weeks?
|
||||
- Does the role make sense for this company's business?
|
||||
- Is the seniority level one that legitimately takes longer to fill?
|
||||
|
||||
### Output format:
|
||||
|
||||
**Assessment:** One of three tiers:
|
||||
- **High Confidence** -- Multiple signals suggest a real, active opening
|
||||
- **Proceed with Caution** -- Mixed signals worth noting
|
||||
- **Suspicious** -- Multiple ghost job indicators, investigate before investing time
|
||||
|
||||
**Signals table:** Each signal observed with its finding and weight (Positive / Neutral / Concerning).
|
||||
|
||||
**Context Notes:** Any caveats (niche role, government job, evergreen position, etc.) that explain potentially concerning signals.
|
||||
|
||||
### Edge case handling:
|
||||
- **Government/academic postings:** Longer timelines are standard. Adjust thresholds (60-90 days is normal).
|
||||
- **Evergreen/continuous hire postings:** If the JD explicitly says "ongoing" or "rolling," note it as context -- this is not a ghost job, it is a pipeline role.
|
||||
- **Niche/executive roles:** Staff+, VP, Director, or highly specialized roles legitimately stay open for months. Adjust age thresholds accordingly.
|
||||
- **Startup / pre-revenue:** Early-stage companies may have vague JDs because the role is genuinely undefined. Weight description vagueness less heavily.
|
||||
- **No date available:** If posting age cannot be determined and no other signals are concerning, default to "Proceed with Caution" with a note that limited data was available. NEVER default to "Suspicious" without evidence.
|
||||
- **Recruiter-sourced (no public posting):** Freshness signals unavailable. Note that active recruiter contact is itself a positive legitimacy signal.
|
||||
|
||||
---
|
||||
|
||||
## Post-evaluación
|
||||
|
||||
**SIEMPRE** después de generar los bloques A-G:
|
||||
|
||||
### 1. Guardar report .md
|
||||
|
||||
Guardar evaluación completa en `reports/{###}-{company-slug}-{YYYY-MM-DD}.md`.
|
||||
|
||||
- `{###}` = siguiente número secuencial (3 dígitos, zero-padded)
|
||||
- `{company-slug}` = nombre de empresa en lowercase, sin espacios (usar guiones)
|
||||
- `{YYYY-MM-DD}` = fecha actual
|
||||
|
||||
**Formato del report:**
|
||||
|
||||
```markdown
|
||||
# Evaluación: {Empresa} — {Rol}
|
||||
|
||||
**Fecha:** {YYYY-MM-DD}
|
||||
**Arquetipo:** {detectado}
|
||||
**Score:** {X/5}
|
||||
**Legitimacy:** {High Confidence | Proceed with Caution | Suspicious}
|
||||
**PDF:** {ruta o pendiente}
|
||||
|
||||
---
|
||||
|
||||
## A) Resumen del Rol
|
||||
(contenido completo del bloque A)
|
||||
|
||||
## B) Match con CV
|
||||
(contenido completo del bloque B)
|
||||
|
||||
## C) Nivel y Estrategia
|
||||
(contenido completo del bloque C)
|
||||
|
||||
## D) Comp y Demanda
|
||||
(contenido completo del bloque D)
|
||||
|
||||
## E) Plan de Personalización
|
||||
(contenido completo del bloque E)
|
||||
|
||||
## F) Plan de Entrevistas
|
||||
(contenido completo del bloque F)
|
||||
|
||||
## G) Posting Legitimacy
|
||||
(contenido completo del bloque G)
|
||||
|
||||
## H) Draft Application Answers
|
||||
(solo si score >= 4.5 — borradores de respuestas para el formulario de aplicación)
|
||||
|
||||
---
|
||||
|
||||
## Keywords extraídas
|
||||
(lista de 15-20 keywords del JD para ATS optimization)
|
||||
```
|
||||
|
||||
### 2. Registrar en tracker
|
||||
|
||||
**SIEMPRE** registrar en `data/applications.md`:
|
||||
- Siguiente número secuencial
|
||||
- Fecha actual
|
||||
- Empresa
|
||||
- Rol
|
||||
- Score: promedio de match (1-5)
|
||||
- Estado: `Evaluada`
|
||||
- PDF: ❌ (o ✅ si auto-pipeline generó PDF)
|
||||
- Report: link relativo al report .md (ej: `[001](reports/001-company-2026-01-01.md)`)
|
||||
|
||||
**Formato del tracker:**
|
||||
|
||||
```markdown
|
||||
| # | Fecha | Empresa | Rol | Score | Estado | PDF | Report |
|
||||
```
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
# Modo: pdf — Generación de PDF ATS-Optimizado
|
||||
|
||||
## Pipeline completo
|
||||
|
||||
1. Lee `cv.md` como fuentes de verdad
|
||||
2. Pide al usuario el JD si no está en contexto (texto o URL)
|
||||
3. Extrae 15-20 keywords del JD
|
||||
4. Detecta idioma del JD → idioma del CV (EN default)
|
||||
5. Detecta ubicación empresa → formato papel:
|
||||
- US/Canada → `letter`
|
||||
- Resto del mundo → `a4`
|
||||
6. Detecta arquetipo del rol → adapta framing
|
||||
7. Reescribe Professional Summary inyectando keywords del JD + exit narrative bridge ("Built and sold a business. Now applying systems thinking to [domain del JD].")
|
||||
8. Selecciona top 3-4 proyectos más relevantes para la oferta
|
||||
9. Reordena bullets de experiencia por relevancia al JD
|
||||
10. Construye competency grid desde requisitos del JD (6-8 keyword phrases)
|
||||
11. Inyecta keywords naturalmente en logros existentes (NUNCA inventa)
|
||||
12. Genera HTML completo desde template + contenido personalizado
|
||||
13. Lee `name` de `config/profile.yml` → normaliza a kebab-case lowercase (e.g. "John Doe" → "john-doe") → `{candidate}`
|
||||
14. Escribe HTML a `/tmp/cv-{candidate}-{company}.html`
|
||||
15. Ejecuta: `node generate-pdf.mjs /tmp/cv-{candidate}-{company}.html output/cv-{candidate}-{company}-{YYYY-MM-DD}.pdf --format={letter|a4}`
|
||||
15. Reporta: ruta del PDF, nº páginas, % cobertura de keywords
|
||||
|
||||
## Reglas ATS (parseo limpio)
|
||||
|
||||
- Layout single-column (sin sidebars, sin columnas paralelas)
|
||||
- Headers estándar: "Professional Summary", "Work Experience", "Education", "Skills", "Certifications", "Projects"
|
||||
- Sin texto en imágenes/SVGs
|
||||
- Sin info crítica en headers/footers del PDF (ATS los ignora)
|
||||
- UTF-8, texto seleccionable (no rasterizado)
|
||||
- Sin tablas anidadas
|
||||
- Keywords del JD distribuidas: Summary (top 5), primer bullet de cada rol, Skills section
|
||||
|
||||
## Diseño del PDF
|
||||
|
||||
- **Fonts**: Space Grotesk (headings, 600-700) + DM Sans (body, 400-500)
|
||||
- **Fonts self-hosted**: `fonts/`
|
||||
- **Header**: nombre en Space Grotesk 24px bold + línea gradiente `linear-gradient(to right, hsl(187,74%,32%), hsl(270,70%,45%))` 2px + fila de contacto
|
||||
- **Section headers**: Space Grotesk 13px, uppercase, letter-spacing 0.05em, color cyan primary
|
||||
- **Body**: DM Sans 11px, line-height 1.5
|
||||
- **Company names**: color accent purple `hsl(270,70%,45%)`
|
||||
- **Márgenes**: 0.6in
|
||||
- **Background**: blanco puro
|
||||
|
||||
## Orden de secciones (optimizado "6-second recruiter scan")
|
||||
|
||||
1. Header (nombre grande, gradiente, contacto, link portfolio)
|
||||
2. Professional Summary (3-4 líneas, keyword-dense)
|
||||
3. Core Competencies (6-8 keyword phrases en flex-grid)
|
||||
4. Work Experience (cronológico inverso)
|
||||
5. Projects (top 3-4 más relevantes)
|
||||
6. Education & Certifications
|
||||
7. Skills (idiomas + técnicos)
|
||||
|
||||
## Estrategia de keyword injection (ético, basado en verdad)
|
||||
|
||||
Ejemplos de reformulación legítima:
|
||||
- JD dice "RAG pipelines" y CV dice "LLM workflows with retrieval" → cambiar a "RAG pipeline design and LLM orchestration workflows"
|
||||
- JD dice "MLOps" y CV dice "observability, evals, error handling" → cambiar a "MLOps and observability: evals, error handling, cost monitoring"
|
||||
- JD dice "stakeholder management" y CV dice "collaborated with team" → cambiar a "stakeholder management across engineering, operations, and business"
|
||||
|
||||
**NUNCA añadir skills que el candidato no tiene. Solo reformular experiencia real con el vocabulario exacto del JD.**
|
||||
|
||||
## Template HTML
|
||||
|
||||
Usar el template en `cv-template.html`. Reemplazar los placeholders `{{...}}` con contenido personalizado:
|
||||
|
||||
| Placeholder | Contenido |
|
||||
|-------------|-----------|
|
||||
| `{{LANG}}` | `en` o `es` |
|
||||
| `{{PAGE_WIDTH}}` | `8.5in` (letter) o `210mm` (A4) |
|
||||
| `{{NAME}}` | (from profile.yml) |
|
||||
| `{{PHONE}}` | (from profile.yml — include with its separator only when `profile.yml` has a non-empty `phone` value; omit both `<span>` and `<span class="separator">` otherwise) |
|
||||
| `{{EMAIL}}` | (from profile.yml) |
|
||||
| `{{LINKEDIN_URL}}` | [from profile.yml] |
|
||||
| `{{LINKEDIN_DISPLAY}}` | [from profile.yml] |
|
||||
| `{{PORTFOLIO_URL}}` | [from profile.yml] (o /es según idioma) |
|
||||
| `{{PORTFOLIO_DISPLAY}}` | [from profile.yml] (o /es según idioma) |
|
||||
| `{{LOCATION}}` | [from profile.yml] |
|
||||
| `{{SECTION_SUMMARY}}` | Professional Summary / Resumen Profesional |
|
||||
| `{{SUMMARY_TEXT}}` | Summary personalizado con keywords |
|
||||
| `{{SECTION_COMPETENCIES}}` | Core Competencies / Competencias Core |
|
||||
| `{{COMPETENCIES}}` | `<span class="competency-tag">keyword</span>` × 6-8 |
|
||||
| `{{SECTION_EXPERIENCE}}` | Work Experience / Experiencia Laboral |
|
||||
| `{{EXPERIENCE}}` | HTML de cada trabajo con bullets reordenados |
|
||||
| `{{SECTION_PROJECTS}}` | Projects / Proyectos |
|
||||
| `{{PROJECTS}}` | HTML de top 3-4 proyectos |
|
||||
| `{{SECTION_EDUCATION}}` | Education / Formación |
|
||||
| `{{EDUCATION}}` | HTML de educación |
|
||||
| `{{SECTION_CERTIFICATIONS}}` | Certifications / Certificaciones |
|
||||
| `{{CERTIFICATIONS}}` | HTML de certificaciones |
|
||||
| `{{SECTION_SKILLS}}` | Skills / Competencias |
|
||||
| `{{SKILLS}}` | HTML de skills |
|
||||
|
||||
## Canva CV Generation (optional)
|
||||
|
||||
If `config/profile.yml` has `canva_resume_design_id` set, offer the user a choice before generating:
|
||||
- **"HTML/PDF (fast, ATS-optimized)"** — existing flow above
|
||||
- **"Canva CV (visual, design-preserving)"** — new flow below
|
||||
|
||||
If the user has no `canva_resume_design_id`, skip this prompt and use the HTML/PDF flow.
|
||||
|
||||
### Canva workflow
|
||||
|
||||
#### Step 1 — Duplicate the base design
|
||||
|
||||
a. `export-design` the base design (using `canva_resume_design_id`) as PDF → get download URL
|
||||
b. `import-design-from-url` using that download URL → creates a new editable design (the duplicate)
|
||||
c. Note the new `design_id` for the duplicate
|
||||
|
||||
#### Step 2 — Read the design structure
|
||||
|
||||
a. `get-design-content` on the new design → returns all text elements (richtexts) with their content
|
||||
b. Map text elements to CV sections by content matching:
|
||||
- Look for the candidate's name → header section
|
||||
- Look for "Summary" or "Professional Summary" → summary section
|
||||
- Look for company names from cv.md → experience sections
|
||||
- Look for degree/school names → education section
|
||||
- Look for skill keywords → skills section
|
||||
c. If mapping fails, show the user what was found and ask for guidance
|
||||
|
||||
#### Step 3 — Generate tailored content
|
||||
|
||||
Same content generation as the HTML flow (Steps 1-11 above):
|
||||
- Rewrite Professional Summary with JD keywords + exit narrative
|
||||
- Reorder experience bullets by JD relevance
|
||||
- Select top competencies from JD requirements
|
||||
- Inject keywords naturally (NEVER invent)
|
||||
|
||||
**IMPORTANT — Character budget rule:** Each replacement text MUST be approximately the same length as the original text it replaces (within ±15% character count). If tailored content is longer, condense it. The Canva design has fixed-size text boxes — longer text causes overlapping with adjacent elements. Count the characters in each original element from Step 2 and enforce this budget when generating replacements.
|
||||
|
||||
#### Step 4 — Apply edits
|
||||
|
||||
a. `start-editing-transaction` on the duplicate design
|
||||
b. `perform-editing-operations` with `find_and_replace_text` for each section:
|
||||
- Replace summary text with tailored summary
|
||||
- Replace each experience bullet with reordered/rewritten bullets
|
||||
- Replace competency/skills text with JD-matched terms
|
||||
- Replace project descriptions with top relevant projects
|
||||
c. **Reflow layout after text replacement:**
|
||||
After applying all text replacements, the text boxes auto-resize but neighboring elements stay in place. This causes uneven spacing between work experience sections. Fix this:
|
||||
1. Read the updated element positions and dimensions from the `perform-editing-operations` response
|
||||
2. For each work experience section (top to bottom), calculate where the bullets text box ends: `end_y = top + height`
|
||||
3. The next section's header should start at `end_y + consistent_gap` (use the original gap from the template, typically ~30px)
|
||||
4. Use `position_element` to move the next section's date, company name, role title, and bullets elements to maintain even spacing
|
||||
5. Repeat for all work experience sections
|
||||
d. **Verify layout before commit:**
|
||||
- `get-design-thumbnail` with the transaction_id and page_index=1
|
||||
- Visually inspect the thumbnail for: text overlapping, uneven spacing, text cut off, text too small
|
||||
- If issues remain, adjust with `position_element`, `resize_element`, or `format_text`
|
||||
- Repeat until layout is clean
|
||||
d. Show the user the final preview and ask for approval
|
||||
e. `commit-editing-transaction` to save (ONLY after user approval)
|
||||
|
||||
#### Step 5 — Export and download PDF
|
||||
|
||||
a. `export-design` the duplicate as PDF (format: a4 or letter based on JD location)
|
||||
b. **IMMEDIATELY** download the PDF using Bash:
|
||||
```bash
|
||||
curl -sL -o "output/cv-{candidate}-{company}-canva-{YYYY-MM-DD}.pdf" "{download_url}"
|
||||
```
|
||||
The export URL is a pre-signed S3 link that expires in ~2 hours. Download it right away.
|
||||
c. Verify the download:
|
||||
```bash
|
||||
file output/cv-{candidate}-{company}-canva-{YYYY-MM-DD}.pdf
|
||||
```
|
||||
Must show "PDF document". If it shows XML or HTML, the URL expired — re-export and retry.
|
||||
d. Report: PDF path, file size, Canva design URL (for manual tweaking)
|
||||
|
||||
#### Error handling
|
||||
|
||||
- If `import-design-from-url` fails → fall back to HTML/PDF pipeline with message
|
||||
- If text elements can't be mapped → warn user, show what was found, ask for manual mapping
|
||||
- If `find_and_replace_text` finds no matches → try broader substring matching
|
||||
- Always provide the Canva design URL so the user can edit manually if auto-edit fails
|
||||
|
||||
## Post-generación
|
||||
|
||||
Actualizar tracker si la oferta ya está registrada: cambiar PDF de ❌ a ✅.
|
||||
Reference in New Issue
Block a user