career-ops

Open-source AI job search: scan job portals, evaluate listings with a structured A-F rubric into a 1.0-5.0 score, tailor your CV, track applications — runs locally in your AI coding CLI (Claude Code, Codex, OpenCode, Antigravity…)

63,650 stars JavaScript Markdown Skills API Spec #ai#ai-agent#anthropic#ats
AI Prompts & Specs

Repository: santifer/career-ops


Stars: 35432

CLAUDE.md

Career-Ops -- AI Job Search Pipeline

Origin

This system was built and used by santifer to evaluate 740+ job offers, generate 100+ tailored CVs, and land a Head of Applied AI role. The archetypes, scoring logic, negotiation scripts, and proof point structure all reflect his specific career search in AI/automation roles.

The portfolio that goes with this system is also open source: cv-santiago.

It will work out of the box, but it's designed to be made yours. If the archetypes don't match your career, the modes are in the wrong language, or the scoring doesn't fit your priorities -- just ask. You (AI Agent) can edit the user's files. The user says "change the archetypes to data engineering roles" and you do it. That's the whole point.

Data Contract (CRITICAL)

There are two layers. Read DATA_CONTRACT.md for the full list.

User Layer (NEVER auto-updated, personalization goes HERE):
- cv.md, config/profile.yml, modes/_profile.md, article-digest.md, portals.yml
- data/, reports/, output/, interview-prep/

System Layer (auto-updatable, DON'T put user data here):
- modes/_shared.md, modes/oferta.md, all other modes
- CLAUDE.md, .mjs scripts, dashboard/, templates/, batch/

THE RULE: When the user asks to customize anything (archetypes, narrative, negotiation scripts, proof points, location policy, comp targets), ALWAYS write to modes/_profile.md or config/profile.yml. NEVER edit modes/_shared.md for user-specific content. This ensures system updates don't overwrite their customizations.

Update Check

On the first message of each session, run the update checker silently:

bash
node update-system.mjs check

Parse the JSON output:
- {"status": "update-available", "local": "1.0.0", "remote": "1.1.0", "changelog": "..."} → tell the user:
> "career-ops update available (v{local} → v{remote}). Your data (CV, profile, tracker, reports) will NOT be touched. Want me to update?"
If yes → run node update-system.mjs apply. If no → run node update-system.mjs dismiss.
- {"status": "up-to-date"} → say nothing
- {"status": "dismissed"} → say nothing
- {"status": "offline"} → say nothing

The user can also say "check for updates" or "update career-ops" at any time to force a check.
To rollback: node update-system.mjs rollback

What is career-ops

AI-powered job search automation built on Claude Code: pipeline tracking, offer evaluation, CV generation, portal scanning, batch processing.

Main Files

| File | Function |
|------|----------|
| data/applications.md | Application tracker |
| data/pipeline.md | Inbox of pending URLs |
| data/scan-history.tsv | Scanner dedup history |
| portals.yml | Query and company config |
| templates/cv-template.html | HTML template for CVs |
| generate-pdf.mjs | Playwright: HTML to PDF |
| article-digest.md | Compact proof points from portfolio (optional) |
| interview-prep/story-bank.md | Accumulated STAR+R stories across evaluations |
| interview-prep/{company}-{role}.md | Company-specific interview intel reports |
| analyze-patterns.mjs | Pattern analysis script (JSON output) |
| followup-cadence.mjs | Follow-up cadence calculator (JSON output) |
| data/follow-ups.md | Follow-up history tracker |
| scan.mjs | Zero-token portal scanner — hits Greenhouse/Ashby/Lever APIs directly, zero LLM cost |
| check-liveness.mjs | Job posting liveness checker |
| liveness-core.mjs | Shared liveness logic (expired signals win over generic Apply text) |
| reports/ | Evaluation reports (format: {###}-{company-slug}-{YYYY-MM-DD}.md). Blocks A-F + G (Posting Legitimacy). Header includes Legitimacy: {tier}. |

OpenCode Commands

When using OpenCode, the following slash commands are available (defined in .opencode/commands/):

| Command | Claude Code Equivalent | Description |
|---------|------------------------|-------------|
| /career-ops | /career-ops | Show menu or evaluate JD with args |
| /career-ops-pipeline | /career-ops pipeline | Process pending URLs from inbox |
| /career-ops-evaluate | /career-ops oferta | Evaluate job offer (A-F scoring) |
| /career-ops-compare | /career-ops ofertas | Compare and rank multiple offers |
| /career-ops-contact | /career-ops contacto | LinkedIn outreach (find contacts + draft) |
| /career-ops-deep | /career-ops deep | Deep company research |
| /career-ops-pdf | /career-ops pdf | Generate ATS-optimized CV |
| /career-ops-training | /career-ops training | Evaluate course/cert against goals |
| /career-ops-project | /career-ops project | Evaluate portfolio project idea |
| /career-ops-tracker | /career-ops tracker | Application status overview |
| /career-ops-apply | /career-ops apply | Live application assistant |
| /career-ops-scan | /career-ops scan | Scan portals for new offers |
| /career-ops-batch | /career-ops batch | Batch processing with parallel workers |
| /career-ops-patterns | /career-ops patterns | Analyze rejection patterns and improve targeting |
| /career-ops-followup | /career-ops followup | Follow-up cadence tracker |

Note: OpenCode commands invoke the same .claude/skills/career-ops/SKILL.md skill used by Claude Code. The modes/* files are shared between both platforms.

First Run — Onboarding (IMPORTANT)

Before doing ANYTHING else, check if the system is set up. Run these checks silently every time a session starts:

1. Does cv.md exist?
2. Does config/profile.yml exist (not just profile.example.yml)?
3. Does modes/_profile.md exist (not just _profile.template.md)?
4. Does portals.yml exist (not just templates/portals.example.yml)?

If modes/_profile.md is missing, copy from modes/_profile.template.md silently. This is the user's customization file — it will never be overwritten by updates.

If ANY of these is missing, enter onboarding mode. Do NOT proceed with evaluations, scans, or any other mode until the basics are in place. Guide the user step by step:

#### Step 1: CV (required)
If cv.md is missing, ask:

"I don't have your CV yet. You can either:

1. Paste your CV here and I'll convert it to markdown

2. Paste your LinkedIn URL and I'll extract the key info

3. Tell me about your experience and I'll draft a CV for you

> Which do you prefer?"

Create cv.md from whatever they provide. Make it clean markdown with standard sections (Summary, Experience, Projects, Education, Skills).

#### Step 2: Profile (required)
If config/profile.yml is missing, copy from config/profile.example.yml and then ask:

"I need a few details to personalize the system:

- Your full name and email

- Your location and timezone

- What roles are you targeting? (e.g., 'Senior Backend Engineer', 'AI Product Manager')

- Your salary target range

> I'll set everything up for you."

Fill in config/profile.yml with their answers. For archetypes and targeting narrative, store the user-specific mapping in modes/_profile.md or config/profile.yml rather than editing modes/_shared.md.

#### Step 3: Portals (recommended)
If portals.yml is missing:

"I'll set up the job scanner with 45+ pre-configured companies. Want me to customize the search keywords for your target roles?"

Copy templates/portals.example.ymlportals.yml. If they gave target roles in Step 2, update title_filter.positive to match.

#### Step 4: Tracker
If data/applications.md doesn't exist, create it:

markdown

Applications Tracker

| # | Date | Company | Role | Score | Status | PDF | Report | Notes |
|---|------|---------|------|-------|--------|-----|--------|-------|

#### Step 5: Get to know the user (important for quality)

After the basics are set up, proactively ask for more context. The more you know, the better your evaluations will be:

"The basics are ready. But the system works much better when it knows you well. Can you tell me more about:

- What makes you unique? What's your 'superpower' that other candidates don't have?

- What kind of work excites you? What drains you?

- Any deal-breakers? (e.g., no on-site, no startups under 20 people, no Java shops)

- Your best professional achievement — the one you'd lead with in an interview

- Any projects, articles, or case studies you've published?

> The more context you give me, the better I filter. Think of it as onboarding a recruiter — the first week I need to learn about you, then I become invaluable."

Store any insights the user shares in config/profile.yml (under narrative), modes/_profile.md, or in article-digest.md if they share proof points. Do not put user-specific archetypes or framing into modes/_shared.md.

After every evaluation, learn. If the user says "this score is too high, I wouldn't apply here" or "you missed that I have experience in X", update your understanding in modes/_profile.md, config/profile.yml, or article-digest.md. The system should get smarter with every interaction without putting personalization into system-layer files.

#### Step 6: Ready
Once all files exist, confirm:

"You're all set! You can now:

- Paste a job URL to evaluate it

- Run /career-ops scan (or /career-ops-scan if using OpenCode) to search portals

- Run /career-ops to see all commands

> Everything is customizable — just ask me to change anything.

> Tip: Having a personal portfolio dramatically improves your job search. If you don't have one yet, the author's portfolio is also open source: github.com/santifer/cv-santiago — feel free to fork it and make it yours."

Then suggest automation:

"Want me to scan for new offers automatically? I can set up a recurring scan every few days so you don't miss anything. Just say 'scan every 3 days' and I'll configure it."

If the user accepts, use the /loop or /schedule skill (if available) to set up a recurring /career-ops scan (or /career-ops-scan if using OpenCode). If those aren't available, suggest adding a cron job or remind them to run /career-ops scan (or /career-ops-scan if using OpenCode) periodically.

Personalization

This system is designed to be customized by YOU (AI Agent). When the user asks you to change archetypes, translate modes, adjust scoring, add companies, or modify negotiation scripts -- do it directly. You read the same files you use, so you know exactly what to edit.

Common customization requests:
- "Change the archetypes to [backend/frontend/data/devops] roles" → edit modes/_profile.md or config/profile.yml
- "Translate the modes to English" → edit all files in modes/
- "Add these companies to my portals" → edit portals.yml
- "Update my profile" → edit config/profile.yml
- "Change the CV template design" → edit templates/cv-template.html
- "Adjust the scoring weights" → edit modes/_profile.md for user-specific weighting, or edit modes/_shared.md and batch/batch-prompt.md only when changing the shared system defaults for everyone

Language Modes

Default modes are in modes/ (English). Additional language-specific modes are available:

- German (DACH market): modes/de/ — native German translations with DACH-specific vocabulary (13. Monatsgehalt, Probezeit, Kündigungsfrist, AGG, Tarifvertrag, etc.). Includes _shared.md, angebot.md (evaluation), bewerben.md (apply), pipeline.md.
- French (Francophone market): modes/fr/ — native French translations with France/Belgium/Switzerland/Luxembourg-specific vocabulary (CDI/CDD, convention collective SYNTEC, RTT, mutuelle, prévoyance, 13e mois, intéressement/participation, titres-restaurant, CSE, portage salarial, etc.). Includes _shared.md, offre.md (evaluation), postuler.md (apply), pipeline.md.
- Japanese (Japan market): modes/ja/ — native Japanese translations with Japan-specific vocabulary (正社員, 業務委託, 賞与, 退職金, みなし残業, 年俸制, 36協定, 通勤手当, 住宅手当, etc.). Includes _shared.md, kyujin.md (evaluation), oubo.md (apply), pipeline.md.

When to use German modes: If the user is targeting German-language job postings, lives in DACH, or asks for German output. Either:
1. User says "use German modes" → read from modes/de/ instead of modes/
2. User sets language.modes_dir: modes/de in config/profile.yml → always use German modes
3. You detect a German JD → suggest switching to German modes

When to use French modes: If the user is targeting French-language job postings, lives in France/Belgium/Switzerland/Luxembourg/Quebec, or asks for French output. Either:
1. User says "use French modes" → read from modes/fr/ instead of modes/
2. User sets language.modes_dir: modes/fr in config/profile.yml → always use French modes
3. You detect a French JD → suggest switching to French modes

When to use Japanese modes: If the user is targeting Japanese-language job postings, lives in Japan, or asks for Japanese output. Either:
1. User says "use Japanese modes" → read from modes/ja/ instead of modes/
2. User sets language.modes_dir: modes/ja in config/profile.yml → always use Japanese modes
3. You detect a Japanese JD → suggest switching to Japanese modes

When NOT to: If the user applies to English-language roles, even at French, German, or Japanese companies, use the default English modes.

Skill Modes

| If the user... | Mode |
|----------------|------|
| Pastes JD or URL | auto-pipeline (evaluate + report + PDF + tracker) |
| Asks to evaluate offer | oferta |
| Asks to compare offers | ofertas |
| Wants LinkedIn outreach | contacto |
| Asks for company research | deep |
| Preps for interview at specific company | interview-prep |
| Wants to generate CV/PDF | pdf |
| Evaluates a course/cert | training |
| Evaluates portfolio project | project |
| Asks about application status | tracker |
| Fills out application form | apply |
| Searches for new offers | scan |
| Processes pending URLs | pipeline |
| Batch processes offers | batch |
| Asks about rejection patterns or wants to improve targeting | patterns |
| Asks about follow-ups or application cadence | followup |

CV Source of Truth

- cv.md in project root is the canonical CV
- article-digest.md has detailed proof points (optional)
- NEVER hardcode metrics -- read them from these files at evaluation time

---

Ethical Use -- CRITICAL

This system is designed for quality, not quantity. The goal is to help the user find and apply to roles where there is a genuine match -- not to spam companies with mass applications.

- NEVER submit an application without the user reviewing it first. Fill forms, draft answers, generate PDFs -- but always STOP before clicking Submit/Send/Apply. The user makes the final call.
- Strongly discourage low-fit applications. If a score is below 4.0/5, explicitly recommend against applying. The user's time and the recruiter's time are both valuable. Only proceed if the user has a specific reason to override the score.
- Quality over speed. A well-targeted application to 5 companies beats a generic blast to 50. Guide the user toward fewer, better applications.
- Respect recruiters' time. Every application a human reads costs someone's attention. Only send what's worth reading.

---

Offer Verification -- MANDATORY

NEVER trust WebSearch/WebFetch to verify if an offer is still active. ALWAYS use Playwright:
1. browser_navigate to the URL
2. browser_snapshot to read content
3. Only footer/navbar without JD = closed. Title + description + Apply = active.

Exception for batch workers (claude -p): Playwright is not available in headless pipe mode. Use WebFetch as fallback and mark the report header with Verification: unconfirmed (batch mode). The user can verify manually later.

---

CI/CD and Quality

- GitHub Actions run on every PR: test-all.mjs (63+ checks), auto-labeler (risk-based: 🔴 core-architecture, ⚠️ agent-behavior, 📄 docs), welcome bot for first-time contributors
- Branch protection on main: status checks must pass before merge. No direct pushes to main (except admin bypass).
- Dependabot monitors npm, Go modules, and GitHub Actions for security updates
- Contributing process: issue first → discussion → PR with linked issue → CI passes → maintainer review → merge

Community and Governance

- Code of Conduct: Contributor Covenant 2.1 with enforcement actions (see CODE_OF_CONDUCT.md)
- Governance: BDFL model with contributor ladder — Participant → Contributor → Triager → Reviewer → Maintainer (see GOVERNANCE.md)
- Security: private vulnerability reporting via email (see SECURITY.md)
- Support: help questions go to Discord/Discussions, not issues (see SUPPORT.md)
- Discord: https://discord.gg/8pRpHETxa4

Stack and Conventions

- Node.js (mjs modules), Playwright (PDF + scraping), YAML (config), HTML/CSS (template), Markdown (data), Canva MCP (optional visual CV)
- Scripts in .mjs, configuration in YAML
- Output in output/ (gitignored), Reports in reports/
- JDs in jds/ (referenced as local:jds/{file} in pipeline.md)
- Batch in batch/ (gitignored except scripts and prompt)
- Report numbering: sequential 3-digit zero-padded, max existing + 1
- RULE: After each batch of evaluations, run node merge-tracker.mjs to merge tracker additions and avoid duplications.
- RULE: NEVER create new entries in applications.md if company+role already exists. Update the existing entry.

TSV Format for Tracker Additions

Write one TSV file per evaluation to batch/tracker-additions/{num}-{company-slug}.tsv. Single line, 9 tab-separated columns:

text
{num}\t{date}\t{company}\t{role}\t{status}\t{score}/5\t{pdf_emoji}\t{num}\t{note}

Column order (IMPORTANT -- status BEFORE score):
1. num -- sequential number (integer)
2. date -- YYYY-MM-DD
3. company -- short company name
4. role -- job title
5. status -- canonical status (e.g., Evaluated)
6. score -- format X.X/5 (e.g., 4.2/5)
7. pdf -- or
8. report -- markdown link num
9. notes -- one-line summary

Note: In applications.md, score comes BEFORE status. The merge script handles this column swap automatically.

Pipeline Integrity

1. NEVER edit applications.md to ADD new entries -- Write TSV in batch/tracker-additions/ and merge-tracker.mjs handles the merge.
2. YES you can edit applications.md to UPDATE status/notes of existing entries.
3. All reports MUST include URL: in the header (between Score and PDF). Include Legitimacy: {tier} (see Block G in modes/oferta.md).
4. All statuses MUST be canonical (see templates/states.yml).
5. Health check: node verify-pipeline.mjs
6. Normalize statuses: node normalize-statuses.mjs
7. Dedup: node dedup-tracker.mjs

Canonical States (applications.md)

Source of truth: templates/states.yml

| State | When to use |
|-------|-------------|
| Evaluated | Report completed, pending decision |
| Applied | Application sent |
| Responded | Company responded |
| Interview | In interview process |
| Offer | Offer received |
| Rejected | Rejected by company |
| Discarded | Discarded by candidate or offer closed |
| SKIP | Doesn't fit, don't apply |

RULES:
- No markdown bold () in status field
- No dates in status field (use the date column)
- No extra text (use the notes column)


README.md

Career-Ops

English | Español | Português (Brasil) | 한국어 | 日本語 | Русский | 繁體中文

<p align="center">
<a href="https://x.com/santifer"><img src="docs/hero-banner.jpg" alt="Career-Ops — Multi-Agent Job Search System" width="800"></a>
</p>

<p align="center">
<em>I spent months applying to jobs the hard way. So I engineered the system I wish I had.</em><br>
Companies use AI to filter candidates. <strong>I gave candidates AI to <em>choose</em> companies.</strong><br>
<em>Now it's open source.</em>
</p>

<p align="center">
<img src="https://img.shields.io/badge/Claude_Code-000?style=flat&logo=anthropic&logoColor=white" alt="Claude Code">
<img src="https://img.shields.io/badge/OpenCode-111827?style=flat&logo=terminal&logoColor=white" alt="OpenCode">
<img src="https://img.shields.io/badge/Codex_(soon)-6B7280?style=flat&logo=openai&logoColor=white" alt="Codex">
<img src="https://img.shields.io/badge/Node.js-339933?style=flat&logo=node.js&logoColor=white" alt="Node.js">
<img src="https://img.shields.io/badge/Go-00ADD8?style=flat&logo=go&logoColor=white" alt="Go">
<img src="https://img.shields.io/badge/Playwright-2EAD33?style=flat&logo=playwright&logoColor=white" alt="Playwright">
<img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="MIT">
<a href="https://discord.gg/8pRpHETxa4"><img src="https://img.shields.io/badge/Discord-5865F2?style=flat&logo=discord&logoColor=white" alt="Discord"></a>
<br>
<img src="https://img.shields.io/badge/EN-blue?style=flat" alt="EN">
<img src="https://img.shields.io/badge/ES-red?style=flat" alt="ES">
<img src="https://img.shields.io/badge/DE-grey?style=flat" alt="DE">
<img src="https://img.shields.io/badge/FR-blue?style=flat" alt="FR">
<img src="https://img.shields.io/badge/PT--BR-green?style=flat" alt="PT-BR">
<img src="https://img.shields.io/badge/KO-white?style=flat" alt="KO">
<img src="https://img.shields.io/badge/JA-red?style=flat" alt="JA">
<img src="https://img.shields.io/badge/ZH--TW-blue?style=flat" alt="ZH-TW">
</p>

---

<p align="center">
<img src="docs/demo.gif" alt="Career-Ops Demo" width="800">
</p>

<p align="center"><strong>740+ job listings evaluated · 100+ personalized CVs · 1 dream role landed</strong></p>

<p align="center"><a href="https://discord.gg/8pRpHETxa4"><img src="https://img.shields.io/badge/Join_the_community-Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" alt="Discord"></a></p>

What Is This

Career-Ops turns any AI coding CLI into a full job search command center. Instead of manually tracking applications in a spreadsheet, you get an AI-powered pipeline that:

- Evaluates offers with a structured A-F scoring system (10 weighted dimensions)
- Generates tailored PDFs -- ATS-optimized CVs customized per job description
- Scans portals automatically (Greenhouse, Ashby, Lever, company pages)
- Processes in batch -- evaluate 10+ offers in parallel with sub-agents
- Tracks everything in a single source of truth with integrity checks

Important: This is NOT a spray-and-pray tool. Career-ops is a filter -- it helps you find the few offers worth your time out of hundreds. The system strongly recommends against applying to anything scoring below 4.0/5. Your time is valuable, and so is the recruiter's. Always review before submitting.

Career-ops is agentic: Claude Code navigates career pages with Playwright, evaluates fit by reasoning about your CV vs the job description (not keyword matching), and adapts your resume per listing.

Heads up: the first evaluations won't be great. The system doesn't know you yet. Feed it context -- your CV, your career story, your proof points, your preferences, what you're good at, what you want to avoid. The more you nurture it, the better it gets. Think of it as onboarding a new recruiter: the first week they need to learn about you, then they become invaluable.

Built by someone who used it to evaluate 740+ job offers, generate 100+ tailored CVs, and land a Head of Applied AI role. Read the full case study.

Features

| Feature | Description |
|---------|-------------|
| Auto-Pipeline | Paste a URL, get a full evaluation + PDF + tracker entry |
| 6-Block Evaluation | Role summary, CV match, level strategy, comp research, personalization, interview prep (STAR+R) |
| Interview Story Bank | Accumulates STAR+Reflection stories across evaluations -- 5-10 master stories that answer any behavioral question |
| Negotiation Scripts | Salary negotiation frameworks, geographic discount pushback, competing offer leverage |
| ATS PDF Generation | Keyword-injected CVs with Space Grotesk + DM Sans design |
| Portal Scanner | 45+ companies pre-configured (Anthropic, OpenAI, ElevenLabs, Retool, n8n...) + custom queries across Ashby, Greenhouse, Lever, Wellfound |
| Batch Processing | Parallel evaluation with claude -p workers |
| Dashboard TUI | Terminal UI to browse, filter, and sort your pipeline |
| Human-in-the-Loop | AI evaluates and recommends, you decide and act. The system never submits an application -- you always have the final call |
| Pipeline Integrity | Automated merge, dedup, status normalization, health checks |

Quick Start

bash

1. Clone and install


git clone https://github.com/santifer/career-ops.git
cd career-ops && npm install
npx playwright install chromium # Required for PDF generation

2. Check setup


npm run doctor # Validates all prerequisites

3. Configure


cp config/profile.example.yml config/profile.yml # Edit with your details
cp templates/portals.example.yml portals.yml # Customize companies

4. Add your CV


Create cv.md in the project root with your CV in markdown

5. Personalize with Claude


claude # Open Claude Code in this directory

Then ask Claude to adapt the system to you:


"Change the archetypes to backend engineering roles"


"Translate the modes to English"


"Add these 5 companies to portals.yml"


"Update my profile with this CV I'm pasting"

6. Start using


Paste a job URL or run /career-ops

The system is designed to be customized by Claude itself. Modes, archetypes, scoring weights, negotiation scripts -- just ask Claude to change them. It reads the same files it uses, so it knows exactly what to edit.

See docs/SETUP.md for the full setup guide.

Usage

Career-ops is a single slash command with multiple modes:

text
/career-ops                → Show all available commands
/career-ops {paste a JD} → Full auto-pipeline (evaluate + PDF + tracker)
/career-ops scan → Scan portals for new offers
/career-ops pdf → Generate ATS-optimized CV
/career-ops batch → Batch evaluate multiple offers
/career-ops tracker → View application status
/career-ops apply → Fill application forms with AI
/career-ops pipeline → Process pending URLs
/career-ops contacto → LinkedIn outreach message
/career-ops deep → Deep company research
/career-ops training → Evaluate a course/cert
/career-ops project → Evaluate a portfolio project

Or just paste a job URL or description directly -- career-ops auto-detects it and runs the full pipeline.

How It Works

text
You paste a job URL or description


┌──────────────────┐
│ Archetype │ Classifies: LLMOps / Agentic / PM / SA / FDE / Transformation
│ Detection │
└────────┬─────────┘

┌────────▼─────────┐
│ A-F Evaluation │ Match, gaps, comp research, STAR stories
│ (reads cv.md) │
└────────┬─────────┘

┌────┼────┐
▼ ▼ ▼
Report PDF Tracker
.md .pdf .tsv

Pre-configured Portals

The scanner comes with 45+ companies ready to scan and 19 search queries across major job boards. Copy templates/portals.example.yml to portals.yml and add your own:

AI Labs: Anthropic, OpenAI, Mistral, Cohere, LangChain, Pinecone
Voice AI: ElevenLabs, PolyAI, Parloa, Hume AI, Deepgram, Vapi, Bland AI
AI Platforms: Retool, Airtable, Vercel, Temporal, Glean, Arize AI
Contact Center: Ada, LivePerson, Sierra, Decagon, Talkdesk, Genesys
Enterprise: Salesforce, Twilio, Gong, Dialpad
LLMOps: Langfuse, Weights & Biases, Lindy, Cognigy, Speechmatics
Automation: n8n, Zapier, Make.com
European: Factorial, Attio, Tinybird, Clarity AI, Travelperk

Job boards searched: Ashby, Greenhouse, Lever, Wellfound, Workable, RemoteFront

Dashboard TUI

The built-in terminal dashboard lets you browse your pipeline visually:

bash
cd dashboard
go build -o career-dashboard .
./career-dashboard --path ..

Features: 6 filter tabs, 4 sort modes, grouped/flat view, lazy-loaded previews, inline status changes.

Project Structure

text
career-ops/
├── CLAUDE.md # Agent instructions
├── cv.md # Your CV (create this)
├── article-digest.md # Your proof points (optional)
├── config/
│ └── profile.example.yml # Template for your profile
├── modes/ # 14 skill modes
│ ├── _shared.md # Shared context (customize this)
│ ├── oferta.md # Single evaluation
│ ├── pdf.md # PDF generation
│ ├── scan.md # Portal scanner
│ ├── batch.md # Batch processing
│ └── ...
├── templates/
│ ├── cv-template.html # ATS-optimized CV template
│ ├── portals.example.yml # Scanner config template
│ └── states.yml # Canonical statuses
├── batch/
│ ├── batch-prompt.md # Self-contained worker prompt
│ └── batch-runner.sh # Orchestrator script
├── dashboard/ # Go TUI pipeline viewer
├── data/ # Your tracking data (gitignored)
├── reports/ # Evaluation reports (gitignored)
├── output/ # Generated PDFs (gitignored)
├── fonts/ # Space Grotesk + DM Sans
├── docs/ # Setup, customization, architecture
└── examples/ # Sample CV, report, proof points

Tech Stack

!Claude Code
!Node.js
!Playwright
!Go
!Bubble Tea

- Agent: Claude Code with custom skills and modes
- PDF: Playwright/Puppeteer + HTML template
- Scanner: Playwright + Greenhouse API + WebSearch
- Dashboard: Go + Bubble Tea + Lipgloss (Catppuccin Mocha theme)
- Data: Markdown tables + YAML config + TSV batch files

Also Open Source

- cv-santiago -- The portfolio website (santifer.io) with AI chatbot, LLMOps dashboard, and case studies. If you need a portfolio to showcase alongside your job search, fork it and make it yours.

About the Author

I'm Santiago -- Head of Applied AI, former founder (built and sold a business that still runs with my name on it). I built career-ops to manage my own job search. It worked: I used it to land my current role.

My portfolio and other open source projects → santifer.io

Buy me a coffee if career-ops helped your job search.

Star History

<a href="https://www.star-history.com/?repos=santifer%2Fcareer-ops&type=timeline&legend=top-left">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=santifer/career-ops&type=timeline&theme=dark&legend=top-left" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=santifer/career-ops&type=timeline&legend=top-left" />
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=santifer/career-ops&type=timeline&legend=top-left" />
</picture>
</a>

Disclaimer

career-ops is a local, open-source tool — NOT a hosted service. By using this software, you acknowledge:

1. You control your data. Your CV, contact info, and personal data stay on your machine and are sent directly to the AI provider you choose (Anthropic, OpenAI, etc.). We do not collect, store, or have access to any of your data.
2. You control the AI. The default prompts instruct the AI not to auto-submit applications, but AI models can behave unpredictably. If you modify the prompts or use different models, you do so at your own risk. Always review AI-generated content for accuracy before submitting.
3. You comply with third-party ToS. You must use this tool in accordance with the Terms of Service of the career portals you interact with (Greenhouse, Lever, Workday, LinkedIn, etc.). Do not use this tool to spam employers or overwhelm ATS systems.
4. No guarantees. Evaluations are recommendations, not truth. AI models may hallucinate skills or experience. The authors are not liable for employment outcomes, rejected applications, account restrictions, or any other consequences.

See LEGAL_DISCLAIMER.md for full details. This software is provided under the MIT License "as is", without warranty of any kind.

Contributors

<a href="https://github.com/santifer/career-ops/graphs/contributors">
<img src="https://contrib.rocks/image?repo=santifer/career-ops" />
</a>

Got hired using career-ops? Share your story!

License

MIT

Let's Connect

![Website](https://santifer.io)
![LinkedIn](https://linkedin.com/in/santifer)
![X](https://x.com/santifer)
![Discord](https://discord.gg/8pRpHETxa4)
![Email](mailto:[email protected])
![Buy Me a Coffee](https://buymeacoffee.com/santifer)