# How Career-Ops Classifies Job Roles: Title Matching, Keyword Scoring, and User Customization

> Discover how Career Ops classifies job roles using title matching keyword scoring and user customization. Learn its unique approach to categorization.

- Repository: [Santiago Fernández de Valderrama/career-ops](https://github.com/santifer/career-ops)
- Tags: how-to-guide
- Published: 2026-08-28

---

**Career-Ops classifies job roles by analyzing job titles against curated keyword dictionaries that map to user-defined archetypes, scoring matches and applying tie-breakers to select the best-fit category.**

The career-ops open-source tool automates job search workflows by intelligently categorizing postings into actionable archetypes. Understanding its classification engine helps you customize targeting and improve match accuracy.

## Title Normalization and Tokenization

The classification pipeline begins with preprocessing. In `role-matcher.mjs`, raw job titles undergo **title normalization**: text is lower-cased, punctuation stripped, and split into tokens. This standardization ensures consistent matching regardless of formatting variations like "Senior Data Scientist – Remote" versus "senior data scientist (remote)".

## Keyword-to-Archetype Mapping

The core classification logic relies on `title-keywords.mjs`, which exports a dictionary mapping **keywords to archetype identifiers**. For example:

- `"machine-learning"` → `"AI Engineer"`
- `"backend"` → `"Backend Engineer"`
- `"frontend"` → `"Frontend Engineer"`

The matcher scans normalized tokens against this dictionary, counting matches per archetype. Multiple keyword hits for the same archetype accumulate scores, providing a ranking mechanism for ambiguous titles.

## Scoring, Tie-Breakers, and Selection

The `classifyRole()` function in `role-matcher.mjs` implements a **scoring and selection algorithm**:

1. Aggregate keyword match counts per archetype
2. Apply tie-breakers for explicit seniority cues ("senior", "lead", "junior", "staff")
3. Return the highest-scoring archetype as the final classification

This approach handles titles spanning multiple domains—such as "Full-Stack Machine Learning Engineer"—by weighing evidence rather than relying on single-keyword matches.

## User-Defined Customization

Career-Ops prioritizes **user customization** through override mechanisms. Before classification, the engine merges default mappings with user-specified keywords from:

- [`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md) — Markdown profile for custom keyword definitions
- [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml) — Structured configuration for target role hierarchies

These overrides take precedence over defaults, enabling personalized targeting for niche specializations or regional job market variations.

## Using the Classification Engine

### CLI Classification

Classify individual titles or batch process from files:

```bash

# Single title classification

node role-matcher.mjs "Senior Data Scientist – Remote"

# Batch processing from file

cat titles.txt | xargs -n1 node role-matcher.mjs

```

### Programmatic API

Import and call directly from other scripts:

```javascript
import { classifyRole } from "./role-matcher.mjs";

const title = "Lead Backend Engineer (Go)";
const archetype = classifyRole(title);
console.log(archetype); // → "Backend Engineer"

```

## Key Source Files

| File | Purpose |
|------|---------|
| `role-matcher.mjs` | Core classification engine—parses titles, scores keywords, returns archetype |
| `title-keywords.mjs` | Default keyword-to-archetype mapping table |
| [`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md) | User-editable profile for custom keyword overrides |
| [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml) | Target role configuration for ranking matches |

## Summary

- Career-Ops **classifies job roles** through normalized title matching against keyword dictionaries
- The **`role-matcher.mjs`** engine scores archetype matches and applies seniority tie-breakers
- **`title-keywords.mjs`** provides the default mapping; users override via **[`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md)**
- Both CLI and programmatic interfaces support flexible integration into job search pipelines

## Frequently Asked Questions

### How does Career-Ops handle ambiguous job titles with multiple possible archetypes?

Career-Ops resolves ambiguity through **scoring accumulation** and **tie-breaker rules**. When titles contain keywords matching multiple archetypes—such as "Full-Stack Data Engineer"—the engine tallies match counts per category and selects the highest score. Explicit seniority keywords ("senior", "lead", "principal") provide secondary ranking signals when scores tie.

### Can I add custom job categories beyond the default archetypes?

Yes. The [`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md) and [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml) files support **user-defined archetypes**. Define new keyword mappings and target role hierarchies in these files; the classification engine merges your overrides with default mappings before processing. This enables niche specializations like "MLOps Engineer" or "Platform Reliability Engineer" not present in the base dictionary.

### What input formats does the classification engine accept?

The `role-matcher.mjs` CLI accepts **single titles as string arguments** or **piped input for batch processing**. The programmatic `classifyRole()` function accepts a single normalized string. Both pathways produce archetype string output suitable for downstream filtering, scoring, and content generation workflows.