What Is the Core Architecture of career-ops? A Deep Dive into the System/User Boundary Design
Career-ops uses a flat-root, two-layer architecture that enforces a strict Data Contract between system code and user data, enabling local-first, AI-agnostic job search automation.
This architecture powers santifer/career-ops, an open-source job search toolkit that runs entirely on your machine and works with any AI coding CLI. The design ensures your sensitive career data never mixes with the tool's source code, making updates safe and reproducible.
The Two-Layer Data Contract
At the heart of career-ops architecture lies the Data Contract documented in DATA_CONTRACT.md and ARCHITECTURE.md. This contract creates an immutable boundary between two layers:
- System layer — Contains all tool code: prompts, scripts, templates, dashboards, and
update-system.mjs. Defined inSYSTEM_PATHS. - User layer — Contains your private data: CV, profile, tracker, reports, and job descriptions. Defined in
USER_PATHS.
Only update-system.mjs can modify system files. User data is Never touched during updates. This separation prevents accidental data loss and enables safe self-upgrades.
Core Design Principles
The three principles in ARCHITECTURE.md【/cache/repos/github.com/santifer/career-ops/main/ARCHITECTURE.md#L9-L12】 shape every architectural decision:
- Local-first — All processing runs against local files. No external service stores your data.
- AI-agnostic — Prompt files in
modes/drive AI logic. Claude Code, Codex, OpenCode, or any AI CLI can execute them. - Human-in-the-loop — The tool prepares content; you review and submit applications.
Architecture Components
The component map in ARCHITECTURE.md【/cache/repos/github.com/santifer/career-ops/main/ARCHITECTURE.md#L36-L50】 breaks into these interconnected parts:
| Component | Function | Key Files |
|---|---|---|
| AI Interface | Reads prompt files and executes commands | AGENTS.md, CLI entry files |
| Prompt Engine | Scoring, evaluation, application logic | modes/*.md, modes/_shared.md |
| Job Discovery | Zero-token job source scanning | scan.mjs, providers/ |
| Evaluation Pipeline | A-H block structured scoring | oferta.md, _shared.md |
| Generation Tools | PDF, LaTeX CV, cover letter creation | generate-*.mjs, templates/ |
| Tracking System | Canonical application tracker | data/applications.md, merge-tracker.mjs |
| Updater | Safe system self-updates | update-system.mjs |
Data Flow Through the System
A typical run follows this sequence, visualized in ARCHITECTURE.md【/cache/repos/github.com/santifer/career-ops/main/ARCHITECTURE.md#L78-L86】:
-
Scan —
node scan.mjspulls public listings via ATS APIs orproviders/modules → writes todata/pipeline.md -
Evaluate —
node oferta.mjsloadsmodes/oferta.md, readscv.md,_profile.md, and the JD → producesreports/NNN-*.md -
Track —
reserve-report-num.mjsandmerge-tracker.mjsatomically updatedata/applications.md -
Generate —
generate-pdf.mjs,build-cv-html.mjscreate application materials -
Human Review — You inspect reports and decide whether to apply
Key Script Entry Points
These top-level scripts implement the architecture's operations:
# Discover jobs without API tokens
node scan.mjs
# Evaluate a specific job posting
codex exec "oferta https://company.com/jobs/123"
# Generate PDF from current CV
node generate-pdf.mjs
# Reserve batch report numbers for parallel processing
node reserve-report-num.mjs --count 5 # Output: 042-046
All scripts enforce the system/user boundary and are located in the repository root alongside ARCHITECTURE.md.
Quality Assurance Mechanisms
The architecture includes automated safeguards described in ARCHITECTURE.md【/cache/repos/github.com/santifer/career-ops/main/ARCHITECTURE.md#L88-L92】:
test-all.mjs— Runs 500+ validation checksupdater-migration-tests.mjs— Verifies system/user separation during updates- CI pipeline — CodeQL, CodeRabbit, and Renovate for continuous validation
Multi-CLI Compatibility
Each AI coding CLI reads a dedicated tiny entry file that forwards to AGENTS.md【/cache/repos/github.com/santifer/career-ops/main/ARCHITECTURE.md#L72-L74】. This design lets the same core logic run on Claude Code, OpenCode, Gemini, and future CLIs without modification.
Critical Source Files
Understanding these files unlocks the full architecture:
| File | Purpose |
|---|---|
ARCHITECTURE.md |
Canonical design documentation and component map |
DATA_CONTRACT.md |
Formal system/user boundary specification |
modes/_shared.md |
Scoring logic, spend-tier routing, global rules |
modes/oferta.md |
Evaluation prompt with A-H block structure |
scan.mjs |
Zero-token job discovery entry point |
providers/ |
Per-job-board modules |
generate-pdf.mjs / build-cv-html.mjs |
Playwright-based document generation |
merge-tracker.mjs |
Atomic TSV tracker updates |
update-system.mjs |
Safe self-update implementation |
AGENTS.md |
Open-agent-skill definition for all CLIs |
Summary
- Career-ops architecture centers on a two-layer Data Contract enforcing strict separation between system code and user data
- Local-first processing ensures no external service ever holds your career information
- AI-agnostic prompt files in
modes/enable compatibility across any AI coding CLI - Human-in-the-loop design keeps you in control of final application decisions
- Safe updates through
update-system.mjsmodify only system paths listed inSYSTEM_PATHS
Frequently Asked Questions
What makes career-ops "local-first"?
All job discovery, evaluation, and document generation runs on your machine using local files. Your CV, profile, and application history never leave your system or get stored by external services. This is enforced by the Data Contract's USER_PATHS definition and implemented in scripts like scan.mjs and generate-pdf.mjs.
How does the system/user boundary prevent data loss?
USER_PATHS explicitly lists directories and files that update-system.mjs will never touch. This means running node update-system.mjs to get the latest career-ops features cannot accidentally overwrite your CV, tracker, or reports. The updater-migration-tests.mjs suite continuously validates this boundary.
Can I use career-ops with AI tools other than Claude Code?
Yes. The architecture is AI-agnostic by design. Prompt logic lives in modes/*.md files that any AI CLI can read. Each supported tool has a thin entry file that routes to AGENTS.md, the canonical skill definition. This works with Codex, OpenCode, Gemini, and compatible alternatives.
What happens if I run scripts in the wrong order?
The tracker system uses atomic operations via reserve-report-num.mjs and merge-tracker.mjs to prevent corruption. However, best practice follows the documented flow: scan → evaluate → track → generate → review. This sequence ensures data/pipeline.md feeds oferta.md evaluation, which correctly populates data/applications.md before document generation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →