Skip to content
Open
6 changes: 4 additions & 2 deletions .agents/skills/career-ops/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: career-ops
description: AI job search command center -- evaluate offers, generate CVs, scan portals, track applications
arguments: mode # Claude Code specific
user-invocable: true
argument-hint: "[scan | deep | pdf | oferta | ofertas | apply | batch | tracker | pipeline | contacto | training | project | interview-prep | update]"
argument-hint: "[scan | deep | pdf | oferta | ofertas | apply | batch | tracker | pipeline | contacto | training | project | interview-prep | add | update]"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
license: MIT
---

Expand Down Expand Up @@ -32,6 +32,7 @@ Determine the mode from `$mode`:
| `batch` | `batch` |
| `patterns` | `patterns` |
| `followup` | `followup` |
| `add` | `add` |

**Auto-pipeline detection:** If `$mode` is not a known sub-command AND contains JD text (keywords: "responsibilities", "requirements", "qualifications", "about the role", "we're looking for", company name + role) or a URL to a JD, execute `auto-pipeline`.

Expand Down Expand Up @@ -63,6 +64,7 @@ Available commands:
/career-ops batch → Batch processing with parallel workers
/career-ops patterns → Analyze rejection patterns and improve targeting
/career-ops followup → Follow-up cadence tracker: flag overdue, generate drafts
/career-ops add {url|text} → Add a project, experience, or skill to your CV permanently

Inbox: add URLs to data/pipeline.md → /career-ops pipeline
Or paste a JD directly to run the full pipeline.
Expand All @@ -82,7 +84,7 @@ Applies to: `auto-pipeline`, `oferta`, `ofertas`, `pdf`, `contacto`, `apply`, `p
### Standalone modes (only their mode file):
Read `modes/{mode}.md`

Applies to: `tracker`, `deep`, `interview-prep`, `training`, `project`, `patterns`, `followup`
Applies to: `tracker`, `deep`, `interview-prep`, `training`, `project`, `patterns`, `followup`, `add`

### Modes delegated to subagent:
For `scan`, `apply` (with Playwright), and `pipeline` (3+ URLs): launch as Agent with the content of `_shared.md` + `modes/{mode}.md` injected into the subagent prompt.
Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ Default modes are in `modes/` (English). Additional language-specific modes are
| Batch processes offers | `batch` |
| Asks about rejection patterns or wants to improve targeting | `patterns` |
| Asks about follow-ups or application cadence | `followup` |
| Wants to add a project, GitHub repo, or experience to their CV | `add` |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

### CV Source of Truth

Expand Down
6 changes: 4 additions & 2 deletions config/profile.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,10 @@ location:
# onsite_availability: "1 week/month in any city"

cv:
output_format: "html" # "html" (default) or "latex"
# CV output format. Default is "latex" (Jake's Resume template, compiled via tectonic/pdflatex).
# Set to "html" to use the HTML/Playwright PDF pipeline instead.
output_format: "latex"
# (Optional) Canva resume design ID for visual CV generation via /career-ops pdf.
# Find it in your Canva design URL: https://www.canva.com/design/DAxxxxxxx/...
# The ID starts with "D" and is 11 characters long.
# canva_resume_design_id: "DAxxxxxxxxx"
# canva_resume_design_id: "DAxxxxxxxxx"
10 changes: 5 additions & 5 deletions generate-latex.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import { existsSync, mkdirSync } from 'fs';

const REQUIRED_SECTIONS = [
'\\\\section{Education}',
'\\\\section{Work Experience}',
'\\\\section{Personal Projects}',
'\\\\section{Experience}',
'\\\\section{Projects}',
'\\\\section{Technical Skills}',
];

Expand Down Expand Up @@ -90,9 +90,9 @@ async function main() {
if (/\\resumeProjectHeading/.test(line)) projectHeadingCount++;
}

// Check pdfgentounicode
// Check pdfgentounicode (accept bare form or wrapped in \ifpdf)
if (!content.includes('\\pdfgentounicode=1')) {
issues.push('Missing \\pdfgentounicode=1 (ATS compatibility)');
issues.push('Missing \\pdfgentounicode=1 (ATS compatibility — wrap in \\ifpdf...\\fi for tectonic/XeLaTeX compatibility)');
}

const fileInfo = await stat(absPath);
Expand Down Expand Up @@ -177,7 +177,7 @@ async function main() {
];
// First pass
execFileSync('pdflatex', pdflatexArgs, { cwd: texDir, stdio: 'pipe', timeout: 120_000 });
// Second pass (resolves referenceS))
// Second pass (resolves references)
execFileSync('pdflatex', pdflatexArgs, { cwd: texDir, stdio: 'pipe', timeout: 120_000 });
}

Expand Down
8 changes: 4 additions & 4 deletions modes/_shared.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@ After detecting archetype, read `modes/_profile.md` for the user's specific fram
| 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 |
| Read | cv.md, _profile.md, article-digest.md, cv-template.tex |
| Write | Generated .tex CV, applications.md, reports .md |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
| Edit | Update tracker |
| Canva MCP | Optional visual CV generation. Duplicate base design, edit text, export PDF. Requires `cv.canva_resume_design_id` in profile.yml. |
| Bash | `node generate-pdf.mjs` |
| Bash | `node generate-latex.mjs` (default); `node generate-pdf.mjs` if `cv.output_format: html` |

### Time-to-offer priority
- Working demo + metrics > perfection
Expand Down Expand Up @@ -226,7 +226,7 @@ These rules apply to ALL generated text that ends up in candidate-facing documen
- "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.
`generate-latex.mjs` compiles the `.tex` file to PDF via `pdflatex` or `tectonic` (auto-detected). For the HTML path, `generate-pdf.mjs` normalizes em-dashes, smart quotes, and zero-width characters to ASCII. Either way, avoid generating non-ASCII characters in the first place.

### Vary sentence structure
- Don't start every bullet with the same verb
Expand Down
193 changes: 193 additions & 0 deletions modes/add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
# Mode: add — Add New Content to CV

Add a project, experience, publication, or skill to `cv.md` and `article-digest.md` so every future CV generation includes it.

## Input Formats

The user can pass:
- **GitHub URL** — `https://github.com/user/repo`
- **Project/portfolio page URL** — any public URL describing a project
- **Research paper URL** — arXiv, ACL, IEEE, journal page
- **Plain text** — freeform description of a project, role, or skill to add
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Multiple items can be passed in one call separated by commas or newlines.

## Pipeline

### Step 1 — Classify the input

For each item, determine its type:

| Signal | Classification |
|--------|----------------|
| `github.com` URL | **project** (fetch repo info + README) |
| arXiv / ACL / DOI / journal URL | **publication** |
| Company name + role + dates in text | **experience** |
| Tech list (comma-separated tools/languages) | **skill** |
| Any other URL or rich description | **project** |

### Step 2 — Fetch content (for URLs)

**GitHub repos:**
1. Use WebFetch to `https://api.github.com/repos/{owner}/{repo}` — extract: `description`, `language`, `topics`, `stargazers_count`, `html_url`
2. Use WebFetch on the raw README (`https://raw.githubusercontent.com/{owner}/{repo}/main/README.md` or `master`) — extract tech stack, features, key outcomes
3. If both fail, use WebFetch on the HTML page directly
Comment thread
coderabbitai[bot] marked this conversation as resolved.

**Other URLs:**
1. Try `browser_navigate` + `browser_snapshot` (Playwright) to render JS-heavy pages
2. Fall back to WebFetch for static pages

**Never invent content.** Only use what is demonstrably on the page. If a page is inaccessible, ask the user to paste the description manually.

### Step 3 — Extract structured data

Extract as much as available. Mark missing fields as `null`:

```
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
name: (string) project/company/paper name
type: project | experience | publication | skill
url: (string|null) canonical URL
dates: (string|null) e.g. "Jan 2025 – Mar 2025" or "2024"
tech_stack: (string[]|null) languages, frameworks, tools
description: (string) 1-2 sentence summary
bullets: (string[]) 2-4 achievement bullets — quantified where possible
hero_metric: (string|null) the single best proof point (e.g. "84% accuracy", "2K stars")
```

**For publications:** also extract `venue` (conference/journal name) and `co-authors`.
**For experience:** also extract `company`, `location`, `role_title`.

### Step 4 — Generate bullets

Write 2-4 bullets using the same style as the existing `cv.md`:
- Action verb first, past tense (present tense only for current roles)
- Quantify outcomes where the source provides numbers
- NEVER invent metrics — use what is on the page or leave unquantified
- Keep it concise and ATS-friendly (no buzzwords)

Example transformation:
> README says "used PyTorch to train a model that classifies 10K images per second"
→ `Trained PyTorch image classifier achieving 10K img/sec throughput`

### Step 5 — Show a preview and ask for confirmation

Before writing anything, display a formatted preview:

```
── PREVIEW ──────────────────────────────────────

[PROJECT] Semantic Search Engine
URL: https://github.com/janesmith/semantic-search
Dates: Jan 2025 – Mar 2025
Tech: Python, PyTorch, FAISS, FastAPI
Bullets:
• Built semantic search engine over 500K documents using dense retrieval (FAISS + bi-encoder)
• Reduced average query latency from 420ms to 38ms via quantized embeddings
• Deployed as FastAPI service with 99.9% uptime over 90-day production run

This will be added to:
→ cv.md (Projects section)
→ article-digest.md (proof points)

Proceed? [yes / edit / skip]
─────────────────────────────────────────────────
```

- **yes / y** → write to files
- **edit** → ask what to change, then show preview again
- **skip / no** → skip this item, move to next

### Step 6 — Write to cv.md

Locate the correct section by type:

| Type | Section in cv.md |
|------|-----------------|
| `project` | `## Projects` |
| `experience` | `## Experience` |
| `publication` | `## Experience` (or `## Publications` if it exists) |
| `skill` | `## Technical Skills` (merge into existing categories) |
| `education` | `## Education` |

**NEVER duplicate.** Before adding, check if the project/company/role name already appears in cv.md. If it does, ask the user whether to update the existing entry or skip.

**Format for projects** (match existing cv.md style):
```markdown
### {name} | {dates}
**Technologies:** {tech_stack joined by ", "}
- {bullet 1}
- {bullet 2}
- {bullet 3}
```

**Format for experience:**
```markdown
### {role_title} | {dates}
**{company}**
- {bullet 1}
- {bullet 2}
- {bullet 3}
```

**Format for publications:**
```markdown
### {title} | {year}
**{venue}** — co-authored with {co-authors}
- {contribution bullet}
- URL: {url}
```

**Format for skills** — merge into the existing `**Category:**` lines. If the tech doesn't fit an existing category, add a new one.

**Placement within section:** Add new projects/experience at the TOP of their section (most recent first). Skills are merged alphabetically within each category.

### Step 7 — Write to article-digest.md

If `article-digest.md` does not exist, create it with this header:
```markdown
# Article & Project Digest

Compact proof points for use during CV generation and evaluations.
```

Append a new entry:
```markdown
## {name}

- **Type:** {type}
- **URL:** {url}
- **Dates:** {dates}
- **Tech:** {tech_stack}
- **Hero metric:** {hero_metric}
- **Summary:** {description}
- **Proof points:**
- {bullet 1}
- {bullet 2}
- {bullet 3}
```

### Step 8 — Confirm and summarize

After writing, report:

```
✅ Added to cv.md:
→ Projects: Semantic Search Engine (Jan 2025 – Mar 2025)

✅ Added to article-digest.md:
→ Semantic Search Engine — hero metric: "38ms query latency"

Future CVs will now include this project and prioritize it for relevant roles.
```

---

## Rules

- **NEVER invent data** that is not on the source page or provided by the user
- **NEVER overwrite** existing entries — only add or merge
- **ALWAYS confirm** before writing (Step 5)
- **Data goes to cv.md and article-digest.md** — these are user-layer files, correct by design
- If the URL is inaccessible, ask the user to paste the content instead of guessing
- If dates are unknown, omit them rather than guessing
- Run `node cv-sync-check.mjs` silently after writing and report any warnings
4 changes: 2 additions & 2 deletions modes/auto-pipeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ Include Block G in the saved report. Add `**Legitimacy:** {tier}` to the report
## Paso 3 — Generar PDF
Read `config/profile.yml`. Check `cv.output_format`:

- If `"latex"`, execute the full pipeline from `modes/latex.md`
- Otherwise (default), execute the full pipeline from `modes/pdf.md`
- If `"html"`, execute the full pipeline from `modes/pdf.md`
- Otherwise (default), execute the full pipeline from `modes/latex.md` (Jake's Resume template)

## Paso 4 — Draft Application Answers (solo si score >= 4.5)

Expand Down
5 changes: 2 additions & 3 deletions modes/latex.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ The template at `templates/cv-template.tex` uses `{{PLACEHOLDER}}` syntax:
| Placeholder | Source |
|-------------|--------|
| `{{NAME}}` | `profile.yml → candidate.full_name` |
| `{{CONTACT_LINE}}` | Phone / City, State / Visa status — built from profile.yml |
| `{{EMAIL_URL}}` | Raw email for `mailto:` URL — must not be LaTeX-escaped (from profile.yml) |
| `{{EMAIL_DISPLAY}}` | Escaped email for display text — LaTeX-special chars like `_` must be escaped, e.g. `first\_name@example.com` |
| `{{LINKEDIN_URL}}` | Full URL with scheme for `\href{}`: e.g. `https://linkedin.com/in/username`. If `profile.yml` stores a bare host+path (no scheme), prepend `https://` before substitution. |
Expand Down Expand Up @@ -123,7 +122,7 @@ All text content MUST be escaped for LaTeX before insertion:
## ATS Rules (same as pdf mode)

- Single-column layout (enforced by template)
- Standard section headers: Education, Work Experience, Personal Projects, Technical Skills
- Standard section headers: Education, Experience, Projects, Technical Skills
- UTF-8, machine-readable via `\pdfgentounicode=1`
- Keywords distributed: first bullet of each role, skills section
- No images, no graphics, no color in body text
Expand All @@ -142,6 +141,6 @@ Same ethical rules as `modes/pdf.md`:
The generated `.tex` file uses only standard CTAN packages (no custom or bundled dependencies):

- `latexsym`, `fullpage`, `titlesec`, `marvosym`, `color`, `verbatim`, `enumitem`
- `hyperref`, `fancyhdr`, `babel`, `tabularx`, `fontawesome5`, `multicol`, `glyphtounicode`
- `hyperref`, `fancyhdr`, `babel`, `tabularx`, `glyphtounicode`

Upload the `.tex` file directly to Overleaf — compiles with no extra configuration.
Loading