Career-Ops Data Contract: User Layer vs System Layer File Separation
Career-Ops enforces a strict data contract that separates personal user data (User Layer) from core application logic (System Layer) to ensure updates never overwrite your customizations.
The open-source Career-Ops repository (santifer/career-ops) implements a defensive architecture that protects your personal information during automated maintenance. This data contract between user layer and system layer files is formally defined in [DATA_CONTRACT.md](https://github.com/santifer/career-ops/blob/main/DATA_CONTRACT.md) and guarantees that system updates can refresh core logic without touching your CV, preferences, or generated reports.
Understanding the Two-Layer Architecture
Career-Ops classifies every file into exactly one of two mutually exclusive layers. This separation creates a hard boundary: the User Layer contains irreplaceable personal data, while the System Layer contains disposable code and templates that can be safely replaced from upstream.
- User Layer: Personal CVs, configuration profiles, custom negotiation scripts, application tracking data, and generated outputs. These files are protected from any automated modification.
- System Layer: Mode definitions, plugin infrastructure, utility scripts, documentation, and templates. These files may be overwritten during updates without data loss.
User Layer Files (Never Auto-Updated)
Files in the User Layer hold personal identity and workflow customizations. According to the source code, the update process must never read, modify, or delete these files.
Personal Data and Configuration
The following paths store your unique professional identity and targets:
cv.md– Your primary Markdown CV.config/profile.yml– Personal identity, target roles, and compensation goals.modes/_profile.md– User-specific archetypes and negotiation scripts.modes/_custom.md– Procedural workflow preferences.voice-dna.md– Stylistic guardrails for generated content.article-digest.md– Proof-points from your portfolio.interview-prep/– STAR stories and company-specific preparation files.portals.yml– Your curated list of job portals.
Generated Output and Plugins
This layer also protects dynamic content and private extensions:
config/plugins.yml– Plugin activation toggles (seeded initially but user-controlled).plugins.local/andplugins.lock– Private plugins and integrity pins.data/– Application tracker, pipeline inbox, scan history, and follow-up logs.writing-samples/*– User-provided writing examples.reports/*andoutput/*– Generated evaluation reports and PDFs.jds/*– Saved job descriptions for analysis.
When writing system scripts that interact with these files, you must append or modify without fear of later overwriting:
// File: scripts/add-company.mjs (System Layer)
import fs from 'fs';
import path from 'path';
export function addPortal(name, url) {
const portalsPath = path.resolve('portals.yml'); // User-layer file
const entry = `- name: ${name}\n url: ${url}\n`;
fs.appendFileSync(portalsPath, entry, 'utf8');
}
System Layer Files (Safe to Update)
The System Layer contains the engine that powers Career-Ops. These files are designed to be ephemeral and can be replaced wholesale during upstream updates.
Core Logic and Templates
modes/_shared.md– Global scoring system and tool definitions.- Mode files like
modes/oferta.mdandmodes/pdf.mdthat drive CLI behavior. - Language-specific directories (
modes/de/*,modes/fr/*). - Agent instruction files:
CLAUDE.md,OPENCODE.md, andAGENTS.md. - Plugin engine:
plugins.mjsand theplugins/directory. - Utility scripts (
*.mjs) and helper modules.
Documentation and Assets
docs/*– Project documentation that may be regenerated.templates/*– UI and PDF templates that evolve with releases.DATA_CONTRACT.md– The contract definition itself.
Because these reside in the System Layer, they can be updated without migration scripts:
// File: utils/notify.mjs (System Layer)
export function notify(msg) {
console.log(`[Career-Ops] ${msg}`);
}
Enforcing the Contract in Code
The separation is maintained by update scripts that check a file's layer membership before performing any operation.
Detecting File Layers Programmatically
The repository includes logic to determine whether a path belongs to the User Layer:
// File: update/check-layer.mjs (System Layer)
import path from 'path';
export function isUserLayer(filePath) {
const userFiles = [
'cv.md',
'config/profile.yml',
'modes/_profile.md',
'modes/_custom.md',
'portals.yml',
// ... additional user-layer paths
];
const rel = path.relative(process.cwd(), filePath);
return userFiles.some(p => rel.startsWith(p));
}
Update mechanisms use this classification to skip any file where isUserLayer() returns true, ensuring compliance with the core rule: If a file is in the User Layer, no update process may read, modify, or delete it.
Summary
- Career-Ops divides all files into a User Layer (personal data) and System Layer (core logic).
- User Layer files—including
cv.md,config/profile.yml,modes/_profile.md, and thedata/directory—are permanently protected from automated updates. - System Layer files—including
modes/_shared.md,plugins.mjs,templates/, and documentation—can be safely replaced during maintenance. - The contract is enforced by update scripts that check file paths against the User Layer registry before performing any write operations.
Frequently Asked Questions
What happens if I modify a system layer file?
Any modifications to System Layer files (such as modes/_shared.md or utils/notify.mjs) will be lost during the next update, as these files are replaced wholesale from the upstream repository. Store customizations in User Layer files like modes/_custom.md instead.
Can I add custom files to the user layer?
Yes. You can create new files in User Layer directories such as interview-prep/ or writing-samples/, and they will be protected from updates. However, avoid naming conflicts with System Layer files to prevent classification errors.
How does the update process protect user data?
The update process references the definitions in DATA_CONTRACT.md and uses helper functions like isUserLayer() to identify protected paths. If a file matches the User Layer criteria, the update script explicitly skips it, ensuring zero-touch modification of personal data.
Where is the data contract formally defined?
The definitive source is [DATA_CONTRACT.md](https://github.com/santifer/career-ops/blob/main/DATA_CONTRACT.md) in the repository root. This System Layer document lists every protected file pattern and establishes the golden rule that User Layer files must never be read, modified, or deleted by automated processes.
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 →