# What Operations Does the Script Layer in CareerOps Handle?

> Explore the CareerOps Script Layer. Discover its Node.js modules that manage data integrity, job scanning, application lifecycle, analytics, automation, and API integration.

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

---

**The Script Layer in CareerOps is a collection of Node-based `.mjs` modules that handle all core data operations—including integrity verification, job board scanning, application lifecycle management, analytics computation, automation orchestration, and web API integration.**

CareerOps organizes its architecture into three distinct layers: the Data Layer (user-generated markdown and TSV files), the Web/UI Layer (React/Next.js front-end), and the **Script Layer**. According to the `santifer/career-ops` source code, the Script Layer serves as the autonomous engine of the system, implementing every operation that reads, mutates, or analyzes tracker data through standalone modules located in the repository root. All higher-level commands, CLI aliases, and web endpoints delegate to this layer to ensure a single source of truth and strict data contract enforcement.

## Data Integrity and Maintenance Operations

The Script Layer enforces canonical data structures and hygiene across the tracker files through dedicated maintenance modules.

### Pipeline Verification and Normalization

The `verify-pipeline.mjs` script performs comprehensive health checks on the entire application pipeline, validating that all TSV and markdown files conform to the expected schema and cross-references. For status standardization, `normalize-statuses.mjs` maps heterogeneous status values (e.g., "Phone Screen", "Phone interview") to canonical enumerated values, ensuring consistent reporting across the fleet.

```bash
npm run verify          # Executes verify-pipeline.mjs

npm run normalize       # Writes canonical statuses via normalize-statuses.mjs

npm run normalize -- --dry-run   # Preview changes without writing

```

### Deduplication and Merging

To handle batch imports and parallel edits, `dedup-tracker.mjs` removes duplicate entries based on content fingerprints, while `merge-tracker.mjs` atomically merges batch TSV files from `batch/tracker-additions/` into the canonical [`applications.md`](https://github.com/santifer/career-ops/blob/main/applications.md) file. This two-phase commit pattern prevents data loss during concurrent modifications.

```bash
npm run add             # Calls add-entry.mjs → writes TSV to batch/tracker-additions/

npm run merge           # Merges TSV into applications.md via merge-tracker.mjs

```

## Job Board Scanning and Discovery

The Script Layer implements zero-token scanners that query ATS APIs and local parsers without requiring authentication tokens, automatically writing new postings to the pipeline.

### Portal Scanning Infrastructure

The `scan.mjs` module orchestrates queries across all configured providers listed in [`portals.yml`](https://github.com/santifer/career-ops/blob/main/portals.yml), dispatching to provider-specific implementations under `providers/`. For example, `providers/workday.mjs` handles Workday-specific parsing logic. For comprehensive discovery, `scan-ats-full.mjs` performs reverse-ATS enumeration to uncover unlisted positions.

```bash
npm run scan            # Executes scan.mjs → queries each provider in portals.yml

```

## Application Lifecycle Management

State transitions and artifact generation are handled exclusively through the Script Layer to maintain atomicity.

### Status Updates and Document Generation

The `set-status.mjs` script updates application statuses atomically, preventing race conditions during concurrent edits. For outbound materials, `generate-pdf.mjs` converts HTML resumes to ATS-friendly PDFs, `generate-cover-letter.mjs` produces tailored cover letters, and `archive-posting.mjs` bundles Job Descriptions (JDs) and CVs into dated archives.

### Entry Creation

New applications enter the system via `add-entry.mjs`, which validates input data, assigns unique identifiers, and stages records in the batch directory for safe eventual consistency.

## Analytics and Reporting Operations

The Script Layer computes sophisticated metrics directly against the local data files without external BI tools.

### Funnel and Gap Analysis

`funnel-velocity.mjs` calculates stage-to-stage conversion rates and time-in-stage metrics, while `salary-gap.mjs` performs compensation analysis against market data. The `upskill.mjs` module aggregates skill requirements from tracked postings to identify learning priorities, and `analyze-patterns.mjs` mines historical data for application success factors.

### Company Intelligence

`company-history.mjs` generates per-company evidence cards by aggregating all interactions, application outcomes, and recruiter notes associated with specific employers.

## Automation and Orchestration

Background processing and LLM evaluations run through dedicated automation scripts.

### Batch Evaluation Pipelines

`batch-evaluate-gemini.mjs` orchestrates headless evaluations using the Gemini API, while `openai-eval.mjs` and `gemini-eval.mjs` provide provider-specific evaluation wrappers. The `rank-pipeline.mjs` script automatically scores and sorts opportunities based on configured criteria using local or remote LLM backends including OpenAI, Gemini, and Ollama.

## System Support and Housekeeping

Environmental diagnostics and maintenance tasks are exposed through utility scripts.

### Environment Validation

The `doctor.mjs` script performs first-run environment checks, verifying Node.js versions, dependency installation, and file system permissions. `validate-portals.mjs` checks the [`portals.yml`](https://github.com/santifer/career-ops/blob/main/portals.yml) configuration for schema correctness, while `check-table-freshness.mjs` monitors data file modification times to alert when local caches are stale.

### System Updates

`update-system.mjs` manages upstream version detection and safe migration of data formats when pulling new releases from the repository.

## Web API Glue Layer

The Script Layer exposes its functionality to the React front-end through thin TypeScript wrappers rather than direct file access.

### API Route Delegation

Files located at `web/src/app/api/*/route.ts` (e.g., [`web/src/app/api/status/route.ts`](https://github.com/santifer/career-ops/blob/main/web/src/app/api/status/route.ts)) locate the appropriate core `.mjs` script and invoke it via `node` subprocess calls. This architecture ensures the web UI never manipulates data files directly; every write operation routes through the Script Layer, guaranteeing contract compliance and audit trail generation.

## Summary

- The **Script Layer in CareerOps** consists of Node-based `.mjs` modules residing in the repository root that implement all business logic.
- **Data integrity** operations include verification (`verify-pipeline.mjs`), normalization (`normalize-statuses.mjs`), deduplication (`dedup-tracker.mjs`), and merging (`merge-tracker.mjs`).
- **Job board scanning** is handled by `scan.mjs` and provider-specific modules under `providers/` (e.g., `providers/workday.mjs`), plus reverse-ATS discovery via `scan-ats-full.mjs`.
- **Application lifecycle** management covers entry creation (`add-entry.mjs`), status updates (`set-status.mjs`), PDF generation (`generate-pdf.mjs`), and archiving (`archive-posting.mjs`).
- **Analytics** scripts compute funnel velocity, salary gaps, skill gaps, and company history without external tools.
- **Automation** scripts provide LLM-backed evaluation and ranking capabilities supporting OpenAI, Gemini, and Ollama backends.
- The **web layer** delegates all data operations to the Script Layer via API routes that spawn Node subprocesses, ensuring strict separation of concerns.

## Frequently Asked Questions

### What file extension do Script Layer modules use in CareerOps?

All Script Layer modules use the `.mjs` extension to explicitly signal ECMAScript module usage. These files reside in the repository root directory and are executed directly via Node.js, either through `node <script>.mjs` invocations or npm aliases defined in [`docs/SCRIPTS.md`](https://github.com/santifer/career-ops/blob/main/docs/SCRIPTS.md).

### How does the CareerOps web interface interact with the Script Layer?

The React/Next.js front-end never accesses data files directly. Instead, API routes under `web/src/app/api/*/route.ts` locate the appropriate root-level `.mjs` script and invoke it using Node subprocesses. This delegation pattern ensures all data mutations respect the canonical pipeline and validation logic implemented in the Script Layer.

### Which script removes duplicate entries from the application tracker?

The `dedup-tracker.mjs` script handles duplicate detection and removal by computing content fingerprints for entries in [`applications.md`](https://github.com/santifer/career-ops/blob/main/applications.md) and the batch addition directory. It can be invoked manually or runs automatically during merge operations to ensure no redundant records persist in the canonical tracker.

### What scripts handle job board automation in CareerOps?

Job board scanning is implemented by `scan.mjs` for standard portal queries and `scan-ats-full.mjs` for reverse ATS discovery. These scripts leverage provider-specific modules located in `providers/` (such as `providers/workday.mjs`) to parse different ATS formats without requiring authentication tokens, writing discovered postings directly to the pipeline.