# How CareerOps Transforms an AI Coding CLI Into a Job Search Command Center

> Discover how CareerOps transforms your AI coding CLI into a job search command center. Normalize arguments, inject prompts, and execute workflows for a powerful job search engine. Learn more!

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

---

**CareerOps acts as a CLI-agnostic orchestration layer that turns any AI coding CLI—whether Claude Code, Copilot, OpenCode, or Qwen—into the central brain for a complete job-search engine by normalizing arguments, injecting mode-specific prompts, and executing data-driven workflows.**

CareerOps is an open-source framework that bridges the gap between general-purpose AI coding assistants and specialized career management tools. According to the `santifer/career-ops` source code, the system wraps your preferred AI CLI with a robust command center capable of scanning job portals, evaluating postings, generating ATS-optimized CVs, and tracking applications through a unified interface.

## The Three-Layer Architecture

The repository implements a tightly-coupled, three-tier architecture that separates CLI normalization from business logic and data persistence.

### CLI Bridge Layer

The **CLI Bridge** provides the uniform entry point `career-ops <mode> …` that any AI coding CLI can invoke. The `run-cli-support.mjs` module normalizes arguments received from different CLI implementations, while `run-prompts.mjs` injects the correct mode-specific prompts (such as `evaluate`, `scan`, or `pdf`) at runtime. This ensures that CLI-specific details like model selection, spend tier, and language output are handled externally, keeping the core engine agnostic.

### Command Center Layer

The **Command Center** encapsulates every job-search workflow as a **mode**. Each mode lives under `modes/` and follows a shared contract defined in [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md). The [`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md) file stores user-layer archetypes and narrative context, while market-specific vocabulary resides in files like [`modes/de/README.md`](https://github.com/santifer/career-ops/blob/main/modes/de/README.md). Plugins extend the system dynamically via `plugins.mjs`, allowing integrations with Notion, GitHub, or custom ATS platforms.

### Data Contract and Store Layer

All state, trackers, and artifacts live in plain-text files under the repository root. The **Data Contract** guarantees that every generated report, CV, or follow-up references canonical sources: [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) for your base resume, [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml) for target roles and salary parameters, and [`data/applications.md`](https://github.com/santifer/career-ops/blob/main/data/applications.md) for the application tracker. When a command runs, the system spawns a short-lived Node process with the repository root as its working directory via `careerOpsRoot()`, ensuring all paths resolve consistently.

## How the AI Coding CLI Integration Works

When you execute a command, the CLI bridge spawns a Node process that loads the appropriate mode script—such as `scan.mjs`, `auto-pipeline.mjs`, or `pdf.mjs`. These scripts read data files via helpers like `find.mjs` or `readInbox.mjs`, call analysis utilities like `jd-skill-gap.mjs` or `funnel-velocity.mjs`, and return structured Markdown reports.

Because **modes are pure data-driven scripts**, you can swap or customize them without touching the core engine. Changing your target role only requires updating [`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md) or [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml), while the CLI bridge handles the rest.

```bash

# Scan dozens of portals for new openings (zero-token mode)

career-ops scan

# Evaluate a specific job posting URL and create a full report

career-ops evaluate https://company.com/jobs/123

# Generate an ATS-optimised PDF for the most recent report (report #045)

career-ops pdf 045

```

## Job Search Modes and Workflows

CareerOps implements distinct operational modes, each optimized for a specific phase of the job search pipeline.

### Zero-Token Scanning

The `scan.mjs` module performs headless scanning of Greenhouse, Lever, and Ashby APIs without consuming LLM tokens. It writes results to [`data/pipeline.md`](https://github.com/santifer/career-ops/blob/main/data/pipeline.md), which serves as the pending-URLs queue for batch processing.

### Intelligent Evaluation

The `auto-pipeline.mjs` orchestration script (invoked via `evaluate` mode) fetches the job description, performs skill-gap analysis, generates a compatibility score, and creates a structured report in [`reports/NNN-company-date.md`](https://github.com/santifer/career-ops/blob/main/reports/NNN-company-date.md). This mode leverages the profile data in [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml) to weight requirements against your actual experience.

### PDF Generation and ATS Optimization

The `pdf.mjs` module (located at `generate-pdf.mjs`) builds an HTML CV using [`templates/cv-template.html`](https://github.com/santifer/career-ops/blob/main/templates/cv-template.html), injects role-specific keywords for ATS compatibility, and renders the final PDF via Playwright. The system also supports LaTeX templates via `templates/cv-template.tex` for academic or research positions.

```bash

# Add a custom role to the tracker

career-ops add \
  --company "Acme Corp" \
  --role "Senior ML Engineer" \
  --date "$(date +%F)" \
  --status "Applied" \
  --score "4.5/5"

# Run batch evaluations against the Gemini model

career-ops batch evaluate \
  --model gemini-1.5-pro \
  --reports data/pipeline.md

```

## Data Integrity and Safety Guards

CareerOps includes **safety guards** that keep the job-search pipeline reliable and data-consistent.

- **`doctor.mjs`**: Validates that essential user files ([`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md), [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml), [`data/applications.md`](https://github.com/santifer/career-ops/blob/main/data/applications.md)) exist before any operation, preventing mid-run failures due to missing configuration.
- **`check-liveness.mjs`**: Uses Playwright to verify that a job posting is still active before evaluation, critical for headless batch operations against stale URLs.
- **`normalize-statuses.mjs`**: Guarantees every tracker entry conforms to canonical states defined in [`templates/states.yml`](https://github.com/santifer/career-ops/blob/main/templates/states.yml), preventing data corruption in [`data/applications.md`](https://github.com/santifer/career-ops/blob/main/data/applications.md).
- **`set-status.mjs`**: Provides atomic tracker updates with validation, ensuring your application pipeline remains accurate when updating entries via CLI or programmatically.

## Summary

- **CLI Agnostic**: `run-cli-support.mjs` and `run-prompts.mjs` normalize any AI coding CLI into a consistent interface.
- **Mode-Driven Architecture**: Workflows live in `modes/` as data-driven scripts, allowing customization without core changes.
- **Canonical Data Sources**: All state persists in plain text ([`data/applications.md`](https://github.com/santifer/career-ops/blob/main/data/applications.md), [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml)), ensuring portability and version control.
- **ATS-Ready Outputs**: `pdf.mjs` generates optimized CVs using [`templates/cv-template.html`](https://github.com/santifer/career-ops/blob/main/templates/cv-template.html) and Playwright rendering.
- **Operational Safety**: `doctor.mjs`, `check-liveness.mjs`, and `set-status.mjs` maintain pipeline integrity through validation and liveness checks.

## Frequently Asked Questions

### Which AI coding CLIs are compatible with CareerOps?

CareerOps works with Claude Code, GitHub Copilot, OpenCode, Qwen, and any other AI coding CLI that can execute Node.js scripts. The `run-cli-support.mjs` module normalizes arguments from each implementation, while `run-prompts.mjs` injects the correct payload regardless of which model or CLI you use.

### How do I customize the evaluation criteria for specific roles?

Update [`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md) to adjust archetypes, narrative framing, and scoring weights, or modify [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml) to change target roles, salary bands, and location preferences. These files define how `auto-pipeline.mjs` scores job descriptions against your profile without requiring changes to the core evaluation logic.

### What file format does the application tracker use?

The tracker uses plain Markdown with TSV-compatible tables in [`data/applications.md`](https://github.com/santifer/career-ops/blob/main/data/applications.md). This format ensures human readability while allowing `set-status.mjs` and `merge-tracker.mjs` to perform atomic updates and data normalization. The [`templates/states.yml`](https://github.com/santifer/career-ops/blob/main/templates/states.yml) file defines the canonical status values (Applied, Phone Screen, Onsite, Offer, Rejected) that all entries must follow.

### How does CareerOps ensure job postings are still active before evaluation?

The `check-liveness.mjs` utility uses Playwright to perform headless browser checks on URLs before processing. This prevents wasted tokens on expired listings and ensures that [`data/pipeline.md`](https://github.com/santifer/career-ops/blob/main/data/pipeline.md) only contains actionable opportunities when running in batch mode.