# How santifer/career-ops Archetype Detection Classifies Job Roles: Token Matching Explained

> Discover how santifer/career-ops archetype detection classifies job roles using token matching and Jaccard similarity. Learn its unique three-stage pipeline for accurate CV framing and negotiation.

- Repository: [Santiago Fernández de Valderrama/career-ops](https://github.com/santifer/career-ops)
- Tags: deep-dive
- Published: 2026-06-13

---

**santifer/career-ops classifies job roles using a deterministic three-stage pipeline that tokenizes job titles, calculates Jaccard similarity scores against six curated archetype keyword sets, and selects the highest match above a 0.6 threshold to drive CV framing and negotiation scripts.**

The santifer/career-ops archetype detection system automatically categorizes every job opportunity into one of six specialized archetypes (such as *AI Platform / LLMOps Engineer* or *Data Engineering*) by analyzing the specific technologies mentioned in role descriptions. This classification engine, implemented in the open-source `santifer/career-ops` repository, relies on a lightweight token-matching algorithm to map diverse job postings to standardized categories. The detection logic spans `role-matcher.mjs`, [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md), and reporting modules like `gemini-eval.mjs`.

## The Three-Stage Detection Pipeline

The archetype classification engine processes each job posting through a strict sequence of tokenization, scoring, and selection. This deterministic approach ensures consistent categorization across thousands of job listings without requiring external API calls or heavy ML inference.

### Stage 1: Tokenizing Job Titles with roleTokens

The pipeline begins in `role-matcher.mjs` (lines 63-70) with the `roleTokens` function, which converts raw job titles into normalized keyword arrays. The function lowercases the input, strips punctuation, and filters out generic stop-words while preserving technology-specific terms.

```javascript
export function roleTokens(role) {
  const text = typeof role === 'string' ? role : String(role ?? '');
  return text
    .toLowerCase()
    .replace(/[^a-z0-9\s]/g, ' ')
    .split(/\s+/)
    .filter(w => (w.length > 3 || SHORT_SPECIALTY.has(w)) && !ROLE_STOPWORDS.has(w));
}

```

The tokenizer discards tokens found in `ROLE_STOPWORDS` (lines 13-32), which contains seniority indicators, contract modes, and generic locations. It retains short specialty acronyms like `api`, `gpu`, or `ios` defined in `SHORT_SPECIALTY` (lines 34-40), ensuring that technical abbreviations survive the filtering process. The resulting array captures only the **discriminating technology words** that distinguish one role from another.

### Stage 2: Calculating Jaccard Similarity Scores

Each archetype is defined by a curated keyword list stored in [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md). The detection algorithm computes a Jaccard-style overlap ratio between the job's token set and each archetype's keyword set. The scoring logic (implemented in `roleFuzzyMatch` within `role-matcher.mjs`) calculates similarity as the size of the intersection divided by the size of the union.

```javascript
// Conceptual implementation based on role-matcher.mjs logic
const jobTokens = new Set(roleTokens(jobTitle));
const archTokens = new Set(archetypeKeywords);
const overlap = [...jobTokens].filter(t => archTokens.has(t));
const unionSize = new Set([...jobTokens, ...archTokens]).size;
const similarity = overlap.length / unionSize;

```

The system enforces a **minimum similarity threshold of 0.6** (lines 100-104 in `role-matcher.mjs`) to prevent false positives. If a job posting shares fewer than 60% of its distinct tokens with an archetype's keyword set, that archetype is disqualified from selection. This threshold ensures that only roles with substantial technology overlap receive classification.

### Stage 3: Selecting the Best Match and Detecting Hybrids

After scoring all six archetypes, the algorithm selects the candidate with the highest similarity score that meets the 0.6 threshold. If no archetype reaches this threshold, the job is classified as **"unknown"** (see `gemini-eval.mjs`, lines 306-311), and reports display `Archetype: unknown`.

When two archetypes both exceed the 0.6 threshold with similar scores, the system marks the posting as a **hybrid** role. According to [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) (line 20), hybrid classifications report both matching archetypes, acknowledging that modern roles often span multiple domains (such as a position requiring both Data Engineering and AI Platform skills).

## Archetype Definitions and Keyword Curation

The canonical definitions for the six archetypes reside in [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md), which serves as the single source of truth for the detection system. Each archetype entry contains a name and a comma-separated keyword list representing core responsibilities and technologies.

```markdown

### AI Platform / LLMOps Engineer

**Keywords:** llm, transformer, prompt-engineering, huggingface, inference, model-ops

```

This file is part of the system layer and is never edited by end users, ensuring consistency across the `role-matcher.mjs` tokenizer and downstream analytics. When `gemini-eval.mjs` generates reports, it extracts the detected archetype and injects it into the header (lines 348-352) using the format:

```markdown
**Archetype:** AI Platform / LLMOps Engineer

```

## Integration with Reporting and Analytics

Once classified, archetypes power the application's core features. The `gemini-eval.mjs` module surfaces the detected archetype in generated reports to guide CV framing and negotiation scripts. For analytics purposes, `analyze-patterns.mjs` parses these archetype headers from report files to aggregate statistics on job market trends by category.

The deterministic nature of this token-based approach means that classifications are reproducible and explainable—every assignment can be traced back to specific keyword overlaps between the job title and the archetype definitions in [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md).

## Summary

- **santifer/career-ops** uses a three-stage pipeline in `role-matcher.mjs` to classify jobs into six archetypes.
- The `roleTokens` function normalizes job titles by removing stop-words and preserving technical terms using `ROLE_STOPWORDS` and `SHORT_SPECIALTY` sets.
- **Jaccard similarity** scores compare job tokens against archetype keywords from [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md), requiring a minimum threshold of **0.6**.
- Roles matching two archetypes are flagged as **hybrids** (per [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md)), while non-matches return **"unknown"**.
- Classifications drive downstream features in `gemini-eval.mjs` and analytics in `analyze-patterns.mjs`.

## Frequently Asked Questions

### What happens if a job matches two archetypes equally well?

When two archetypes both exceed the 0.6 similarity threshold, santifer/career-ops marks the role as a **hybrid** and reports both classifications. This handling, documented in [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) (line 20), ensures that cross-functional roles (such as those combining data engineering and ML operations) receive accurate multi-category labels rather than forcing a false binary choice.

### Where are the archetype keywords defined in santifer/career-ops?

The six archetype definitions and their associated keyword lists are stored in **[`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md)**. This file serves as the system-level source of truth, containing formatted entries like "### AI Platform / LLMOps Engineer" followed by curated technology keywords. The `role-matcher.mjs` module loads these definitions to perform classification against incoming job postings.

### What is the minimum similarity threshold for classification?

The system requires a **Jaccard similarity score of at least 0.6** between the job's token set and an archetype's keyword set. This threshold is hardcoded in `role-matcher.mjs` (lines 100-104) to filter out weak matches and ensure that only positions with substantial technology overlap receive a specific archetype assignment.

### How does the system handle job titles without matching archetype keywords?

If no archetype achieves the 0.6 similarity threshold, the detection pipeline returns **"unknown"** as the classification. As shown in `gemini-eval.mjs` (lines 306-311), these cases are explicitly handled in report generation, displaying `Archetype: unknown` and skipping archetype-specific CV framing while still preserving the raw job data for manual review.