# CareerOps Layered Agentic Architecture: A Three-Tier System for Autonomous Job Search

> Explore CareerOps layered agentic architecture a three-tier system for autonomous job search. This design separates scripts data and AI logic for efficient automation.

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

---

**CareerOps implements a strict three-layered agentic architecture that separates system scripts, user data, and AI decision logic to enable autonomous, side-effect-free job search automation.**

The `santifer/career-ops` repository demonstrates how to build a modular, AI-agnostic job application assistant using a layered agentic architecture. By dividing responsibilities across distinct tiers—executable code, personal data stores, and Markdown-based reasoning engines—the system ensures that specialized agents operate within strict boundaries without risking data corruption or unintended side effects.

## The Three Layers of the CareerOps Stack

The architecture is organized into three primary layers that reflect distinct concerns: system execution, user data management, and AI-driven decision logic.

### System Layer: Execution Agents

The **System Layer** contains the code that runs the tool, including scripts, CLI entry points, and updater logic. According to [`ARCHITECTURE.md`](https://github.com/santifer/career-ops/blob/main/ARCHITECTURE.md), this layer *never touches user-generated files*.

Key components include:
- `scan.mjs` – The discovery agent that scrapes public ATS APIs
- `providers/` – Pluggable job-source plugins for extending discovery
- `update-system.mjs` – Self-update agent that upgrades only system files
- [`AGENTS.md`](https://github.com/santifer/career-ops/blob/main/AGENTS.md) – Entry point mapping for compatible AI coding CLIs

This layer acts as the operational brain of the platform, handling file I/O operations, network requests, and system maintenance while maintaining read-only access to user configurations.

### User Layer: Data Sovereignty

The **User Layer** stores the candidate’s personal data, CV, application tracker, and customizations. Files in this tier include [`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), [`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md), and the `data/` and `reports/` directories.

A critical architectural constraint governs this layer: **the system layer reads from here but never modifies it**. User data resides in the [`data/applications.md`](https://github.com/santifer/career-ops/blob/main/data/applications.md) tracker and the `jds/` directory for job descriptions, serving as the single source of truth that persists across system upgrades.

### AI-Prompt Layer: Reasoning Logic

The **AI-Prompt Layer** consists of Markdown "brain" files that encode scoring rules, archetype detection, and generation logic. These files are read by any AI-coding CLI (such as Claude Code or OpenCode) or by lightweight evaluators.

Core prompt files include:
- [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) – Core scoring engine used by every evaluation agent
- [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) – Full evaluation workflow covering blocks A through H
- Locale-specific variants (e.g., [`modes/de/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/de/oferta.md)) for internationalization

Because this layer consists solely of Markdown text files, the system remains **AI-agnostic**—the "brain" can be swapped without changing system code.

## How the Agentic Pipeline Executes

The layers interact through a strict six-stage pipeline flow, with each script acting as a focused autonomous agent that receives input and emits output without side effects on unrelated layers.

### 1. Discovery via `scan.mjs`

The discovery agent scrapes public job boards using pluggable providers and writes raw listings to [`data/pipeline.md`](https://github.com/santifer/career-ops/blob/main/data/pipeline.md).

```bash

# Populate the pipeline with fresh opportunities

node scan.mjs

```

### 2. Liveness Validation via `check-liveness.mjs`

Before incurring evaluation costs, the liveness agent filters out closed postings.

```bash

# Verify a posting is still live (zero-token operation)

node check-liveness.mjs <url>

```

### 3. Evaluation via AI-Prompt Agents

The evaluation agent reads the job description, the user’s [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md), and the scoring rules in [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) and [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) to generate a structured report.

```bash

# Create reports/NNN-*.md and update the tracker

node oferta.mjs <report-num> <url>

```

### 4. Tracking via `merge-tracker.mjs`

This agent atomically updates [`data/applications.md`](https://github.com/santifer/career-ops/blob/main/data/applications.md), preserving the single source of truth for application statuses.

### 5. Document Generation via `generate-pdf.mjs`

PDF and LaTeX generators produce final CVs and cover letters using templates in `templates/`.

```bash

# Generate output/cv.pdf from cv.md + templates

node generate-pdf.mjs cv

```

### 6. Self-Update via `update-system.mjs`

The updater safely upgrades only the system layer while leaving the user layer untouched.

```bash

# Apply latest system updates without touching personal data

node update-system.mjs apply

```

## Boundary Enforcement and AI Agnosticism

The **agentic nature** of CareerOps derives from strict boundary enforcement between layers. Scripts in the system layer possess write access only to temporary working directories and the [`data/pipeline.md`](https://github.com/santifer/career-ops/blob/main/data/pipeline.md) buffer, while maintaining read-only access to user files like [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml).

The AI-prompt layer reinforces this design by externalizing all decision logic into Markdown files. Because [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) and [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) contain pure reasoning instructions rather than executable code, any compatible AI model can serve as the evaluation agent without requiring system modifications or API-specific integrations.

## Key Files in the Architecture

| File | Layer | Responsibility |
|------|-------|----------------|
| [`ARCHITECTURE.md`](https://github.com/santifer/career-ops/blob/main/ARCHITECTURE.md) | Documentation | High-level overview of layer interactions |
| `scan.mjs` | System | Discovery agent for job board scraping |
| [`providers/README.md`](https://github.com/santifer/career-ops/blob/main/providers/README.md) | System | Extension point for new job-source plugins |
| [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) | AI-Prompt | Core scoring engine (archetype detection) |
| [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) | AI-Prompt | Complete evaluation workflow blocks A-H |
| `update-system.mjs` | System | Safe upgrade mechanism respecting boundaries |
| [`data/applications.md`](https://github.com/santifer/career-ops/blob/main/data/applications.md) | User | Canonical application tracker database |
| [`AGENTS.md`](https://github.com/santifer/career-ops/blob/main/AGENTS.md) | System | CLI entry point mappings for AI tools |

## Summary

- **Three-layer separation** prevents system updates from corrupting user data and ensures AI logic remains vendor-agnostic.
- **Six-stage pipeline** moves from job discovery (`scan.mjs`) through evaluation ([`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md)) to document generation (`generate-pdf.mjs`).
- **Strict write boundaries** allow the system layer to read [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) and [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml) but prohibit modification of user-layer files.
- **Markdown-based reasoning** in [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) enables any AI-coding CLI to act as the evaluation agent without code changes.

## Frequently Asked Questions

### What distinguishes CareerOps as "agentic" rather than a simple script collection?

CareerOps implements **autonomous agents** that follow the stimulus-response pattern: each script (`scan.mjs`, `oferta.mjs`, `generate-pdf.mjs`) receives specific inputs (URLs, file paths) and produces deterministic outputs (Markdown reports, PDFs) while maintaining isolation from other layers. The architecture treats these scripts as independent workers that coordinate through the filesystem rather than monolithic application logic, enabling parallel execution and failure isolation.

### How does the System Layer avoid modifying User Layer files?

The architecture enforces a **read-only contract** where system scripts access user data like [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) and [`data/applications.md`](https://github.com/santifer/career-ops/blob/main/data/applications.md) exclusively for reading. Write operations from agents such as `merge-tracker.mjs` target specific controlled files within the user layer's structure, while `update-system.mjs` explicitly excludes user directories from its file operations. This separation is documented in [`ARCHITECTURE.md`](https://github.com/santifer/career-ops/blob/main/ARCHITECTURE.md) as "The Two Layers: The Data Contract."

### Can CareerOps work with AI models other than Claude or OpenCode?

Yes. Because the **AI-Prompt Layer** consists of standard Markdown files ([`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md), `modes/oferta.mjs`) containing natural language instructions and scoring rubrics, any AI coding assistant that can read project files can serve as the reasoning engine. The [`AGENTS.md`](https://github.com/santifer/career-ops/blob/main/AGENTS.md) file standardizes entry points across different CLI tools, making the system truly AI-agnostic.

### What occurs during the Evaluation stage of the pipeline?

During **Evaluation**, the system invokes the AI-prompt agent (typically via `oferta.mjs`) which loads the job description from `jds/`, the candidate profile from [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md), and the scoring rules from [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) blocks A through H. The agent generates a structured Markdown report saved to `reports/NNN-*.md` containing fit scores and archetype analysis, then `merge-tracker.mjs` atomically appends this entry to [`data/applications.md`](https://github.com/santifer/career-ops/blob/main/data/applications.md) without overwriting existing records.