How the Layered Agent Instruction Model Works in Career-Ops: A 3-Tier Architecture
Career-Ops implements a hierarchical instruction stack that separates system logic from user configuration through three distinct tiers—system, profile, and custom—ensuring safe updates and personalized AI behavior across multiple CLI tools.
The open-source Career-Ops repository (santifer/career-ops) manages career optimization workflows through a sophisticated layered agent instruction model that keeps core functionality stable while allowing deep user customization. This architecture ensures that updates to the underlying engine never overwrite personal settings, creating a safe environment for tailoring AI behavior to individual career narratives and target roles.
The Three Tiers of the Instruction Stack
The model organizes instructions into a hierarchical stack where higher layers override lower ones. Each tier serves a distinct purpose and resides in specific files within the repository.
System Layer (modes/_shared.md)
The system layer provides the generic "brain" that powers every operational mode, including scoring algorithms, evaluation logic, job scanning, and PDF generation. Located in modes/_shared.md and various *.mjs scripts, this tier loads first and establishes baseline behavior shared across all supported CLIs. According to the Career-Ops source code, this layer contains versioned core logic that updates automatically via the update-system.mjs utility, ensuring all users receive improvements to scoring and scanning without manual intervention.
Profile Layer (modes/_profile.md, config/profile.yml)
The profile layer personalizes the user's narrative, professional archetypes, target roles, and salary goals. Configuration lives in modes/_profile.md and config/profile.yml, allowing users to override system defaults with personal preferences. When a value exists in the profile—such as language.output: fr for French prose—it masks the corresponding system default without modifying core files, enabling localized output while retaining the English-based scoring engine.
Custom Layer (modes/_custom.md)
The custom layer handles procedural tweaks and workflow enforcements that fall outside system or profile concerns. Users create this layer by copying modes/_custom.template.md to modes/_custom.md, then appending rules like skipping specific job types or altering output formats. Applied last in the stack, this tier enables behavioral changes without touching shared core logic, allowing users to enforce domain-specific constraints such as automatically rejecting internship positions.
How the Agent Dispatcher Orchestrates Prompt Assembly
The agent dispatcher, defined in AGENTS.md, maps each supported CLI (Claude, Codex, Opencode, Gemini, etc.) to a corresponding skill file (e.g., CLAUDE.md, CODEX.md). Each skill file loads the three instruction tiers in strict sequence:
[system-layer] → [profile-layer] → [custom-layer] → [user query]
This CLI-agnostic entry point guarantees identical core behavior across different AI assistants while allowing each tool to supply wrapper-specific arguments. The final assembled prompt respects the Data Contract outlined in DATA_CONTRACT.md, ensuring that layers remain additive rather than destructive, with user queries always receiving the accumulated context of all previous tiers.
Separation of Concerns and Safe Updates
The architecture enforces strict separation of concerns through file path segregation. The update-system.mjs script only modifies files listed under SYSTEM_PATHS, which includes modes/_shared.md and *.mjs scripts, while explicitly excluding user files like cv.md, config/profile.yml, modes/_profile.md, and modes/_custom.md.
This design implements an override hierarchy where profile and custom layers safely mask system defaults. When the updater runs, it preserves all personalization while refreshing the generic logic, eliminating the risk of update-driven configuration loss. Additionally, every layer terminates with a human-in-the-loop confirmation request, ensuring no automated process can bypass user approval for critical actions.
Practical Implementation Examples
The following examples demonstrate how to interact with the layered model using different CLIs and configuration overrides.
Run a standard job evaluation using Opencode:
opencode run "career-ops evaluate https://example.com/job/123"
Override default language output via the profile layer by editing config/profile.yml:
language:
output: fr
The next execution will generate French prose while maintaining the English scoring core from the system layer.
Add a custom rule in modes/_custom.md to skip internship positions:
if job.title contains "intern" then set status to SKIP
This custom layer instruction applies to all subsequent evaluations without modifying shared system files.
Summary
- The Career-Ops layered agent instruction model uses three tiers: system (
modes/_shared.md), profile (modes/_profile.md,config/profile.yml), and custom (modes/_custom.md). - The agent dispatcher in
AGENTS.mdorchestrates prompt assembly by loading skill files that stack tiers in order: system, then profile, then custom. - Separation of concerns ensures
update-system.mjsonly touchesSYSTEM_PATHSfiles, protecting user customizations from automatic updates. - The architecture is CLI-agnostic, providing identical behavior across Claude, Codex, Opencode, and Gemini through standardized skill files that reference the same instruction stack.
Frequently Asked Questions
What is the order of precedence in the Career-Ops instruction stack?
The instruction stack follows a strict loading sequence defined in the skill files referenced by AGENTS.md. The system layer loads first to establish baseline behavior, followed by the profile layer which overrides defaults with user-specific values, and finally the custom layer which applies last-minute procedural tweaks. When conflicts occur, higher layers mask lower layers, ensuring personal settings always take precedence over generic defaults.
How does Career-Ops prevent system updates from overwriting my custom settings?
The updater script update-system.mjs strictly adheres to the SYSTEM_PATHS whitelist, which only includes core system files like modes/_shared.md and *.mjs scripts. User files including config/profile.yml, modes/_profile.md, and modes/_custom.md reside outside these paths and remain untouched during updates. This architectural boundary, combined with the Data Contract defined in DATA_CONTRACT.md, guarantees that personal configurations persist across system upgrades.
Can I use Career-Ops with different AI coding assistants?
Yes, the layered model is CLI-agnostic by design. The agent dispatcher in AGENTS.md maps each supported CLI—whether Claude, Codex, Opencode, or Gemini—to a specific skill file (e.g., CLAUDE.md, CODEX.md). Each skill file references the same three-tier instruction stack, ensuring consistent behavior across different AI tools while accommodating CLI-specific wrapper arguments and invocation patterns.
What file should I edit to change my target roles or language preferences?
Modify config/profile.yml for structured data like target roles, salary goals, and language output settings. For narrative personalization and professional archetype definitions, edit modes/_profile.md. Both files reside in the profile layer and automatically override corresponding system defaults without altering core logic. The system recognizes these changes immediately upon the next CLI invocation.
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 →