career-ops -- Router skill

AI job search command center -- evaluate offers, generate CVs, scan portals, track applications.

by career-ops-hq·MIT license·★ 73,406 Stars on the repo·GitHub ↗

Use now

Files of career-ops -- Router

career-ops-hq/main1 file shown
SKILL.md
Show the full text207 lines

career-ops -- Router

career-ops is a multi-CLI job-search command center. The routing below is shared across supported agent CLIs even when the invocation surface differs.

Project Root Resolution

Before reading any repo-relative path, derive PROJECT_ROOT from this loaded SKILL.md: start at the skill file's directory and walk upward until the nearest directory containing both AGENTS.md and modes/. Resolve every path in this router (modes/, config/, data/, scripts, templates, and output paths) against PROJECT_ROOT, never against the process's current working directory. This is required even when the checkout itself is nested (for example Development\\career-ops) or the command starts from a subdirectory. If those two sentinels cannot be found, stop and locate the career-ops checkout before reading or writing files.

Invocation Notes

  • CLIs with slash-command registration can expose this router as /career-ops.
  • In Cursor, this skill lives at .cursor/skills/career-ops/ and is auto-discovered; ask for a mode by name, or paste a JD/URL to trigger auto-pipeline.
  • In Pi, this skill is auto-discovered from .agents/skills/career-ops/ and exposed as /skill:career-ops; AGENTS.md loads from the repo root as project context, so there is no wrapper file. Headless Pi workers use pi -p "prompt". Project skill discovery follows Pi's per-folder trust decision: /trust applies to future Pi processes, so restart pi before invoking /skill:career-ops (-a trusts a single run and needs no restart).
  • Interactive Codex sessions use codex in the repo root. Slash commands are not guaranteed in Codex, so ask Codex to run the same mode by name if /career-ops is unavailable.
  • Headless Codex workers use codex exec "prompt".
  • The routing semantics below stay the same regardless of whether the entrypoint is a slash command or a natural-language prompt.

Codex prompt examples that map to the same router semantics:

Evaluate this JD with career-ops auto-pipeline: https://company.com/jobs/123
Run the career-ops scan mode and summarize new matches.
Run the career-ops pipeline mode for data/pipeline.md.
Run the career-ops pdf mode for the latest evaluated role.
Run the career-ops tracker mode and summarize the current statuses.

Mode Routing

Determine the mode from $mode:

Input Mode
(empty / no args) discovery -- Show command menu
JD text or URL (no sub-command) auto-pipeline
oferta oferta
ofertas ofertas
contacto contacto
deep deep
interview-prep interview-prep
interview interview
master-profile master-profile
eu-swe regional/eu-swe
interview/plan interview/plan
interview/practice interview/practice
interview/debrief interview/debrief
pdf pdf
text text
latex latex
latex-tex latex-tex
email email
add add
expand expand
training training
project project
tracker tracker
agent-inbox agent-inbox
inbox agent-inbox
pipeline pipeline
apply apply
scan scan
discover discover
batch batch
patterns patterns
offer-prep offer-prep
titles titles
upskill upskill
followup followup
reply-watch reply-watch
outcome outcome
interview-redflag interview-redflag
update update
cover cover

Auto-pipeline detection: If $mode is not a known sub-command AND contains JD text (keywords: "responsibilities", "requirements", "qualifications", "about the role", "we're looking for", company name + role) or a URL to a JD, execute auto-pipeline.

If $mode is not a sub-command AND doesn't look like a JD, show discovery.


Output Language Directive

Before executing any mode, read config/profile.yml if it exists and resolve:

  • language.output → ISO language code for human-facing output. Default: en.
  • language.modes_dir → optional market-mode directory. This controls market vocabulary and local evaluation rules only. It may be a single string (one declared market, the historical default) or a list of declared candidate markets for a candidate genuinely running parallel campaigns in more than one market at once (#3793), e.g. modes_dir: [modes/de, modes/zh]. When a list is given, the FIRST entry is primary and supplies the evaluation-mode file (Block A-F rules can only run from one market's file at a time); EVERY declared market's _shared.md is loaded into context. modes itself is a valid declared candidate for markets without a localized directory; when first it supplies modes/oferta.md, and its baseline modes/_shared.md is loaded once. Per posting, judge which declared market actually applies from the JD's own MARKET signals (hiring-entity jurisdiction, currency, benefits/legal vocabulary) — never from the JD's language alone. If genuinely ambiguous, an interactive session asks and stops before persistence; an unattended worker uses the primary market and records that fallback in the report header or Block G.

Inject this directive after loading the mode instructions and before producing any user-visible content:

Write all human-facing output in {language.output} regardless of the language of these instructions or of the job description. This includes reports, tracker notes, PDFs, cover letters, outreach, interview prep, form answers, and summaries. If language.modes_dir supplies market-specific vocabulary (one market, or several declared at once), keep the market logic but explain terms in {language.output} when needed.

language.output is authoritative for prose. modes_dir is market context; it must not force the prose language.


Discovery Mode (no arguments)

If your CLI supports /career-ops, show this menu. In Codex, surface the same options in plain text and map the requested mode the same way.

Concrete equivalents for Codex prompt-driven sessions:

/career-ops {JD}           ↔ "Evaluate this JD with career-ops auto-pipeline: {JD or URL}"
/career-ops scan           ↔ "Run the career-ops scan mode and summarize new matches."
/career-ops pipeline       ↔ "Run the career-ops pipeline mode for data/pipeline.md."
/career-ops pdf            ↔ "Run the career-ops pdf mode for the latest evaluated role."
/career-ops email          ↔ "Run the career-ops email mode for the latest evaluated role."
/career-ops tracker        ↔ "Run the career-ops tracker mode and summarize the current statuses."

Show this menu:

career-ops -- Command Center

Available commands:
  /career-ops {JD}      → AUTO-PIPELINE: evaluate + report + PDF + tracker (paste text or URL)
  /career-ops pipeline  → Process pending URLs from inbox (data/pipeline.md)
  /career-ops oferta    → Evaluation only A-F (no auto PDF)
  /career-ops ofertas   → Compare and rank multiple offers
  /career-ops contacto  → LinkedIn power move: find contacts + draft message
  /career-ops deep      → Deep research prompt about company
  /career-ops interview-prep → Generate company-specific interview prep doc
  /career-ops interview    → Interactive profile/CV onboarding interview
  /career-ops master-profile → Import, review, and validate your Master Career Profile
  /career-ops eu-swe    → Calibrate a European SWE application before CV/apply/interview
  /career-ops interview/plan → Time-blocked prep plan for an upcoming interview
  /career-ops interview/practice → Practice interview, one question at a time with feedback
  /career-ops interview/debrief → Post-interview debrief: close gaps, predict next round
  /career-ops pdf       → PDF only, ATS-optimized CV
  /career-ops text      → Tailored markdown CV (mirrors cv.md, no PDF)
  /career-ops latex     → Export CV as LaTeX/Overleaf .tex
  /career-ops latex-tex → Tailor your own resume.tex in place (opt-in; cv.md stays default)
  /career-ops cover     → Cover letter: standalone JD paste or /career-ops cover {slug}
  /career-ops email     → Formal application email draft (draft-only; never sends, submits, or clicks)
  /career-ops add       → Add a project/paper/role to your CV (fetch + preview + confirm)
  /career-ops expand    → Auto-discover and add missing competencies from profile links
  /career-ops training  → Evaluate course/cert against North Star
  /career-ops project   → Evaluate portfolio project idea
  /career-ops tracker   → Application status overview
  /career-ops agent-inbox → Queue/drain requests for the next session (data/agent-inbox.md)
  /career-ops apply     → Live application assistant (reads form + generates answers)
  /career-ops scan      → Scan portals and discover new offers
  /career-ops discover  → Resolve a company list to scannable ATS boards + append to portals.yml (zero-token)
  /career-ops batch     → Batch processing with parallel workers
  /career-ops patterns  → Analyze rejection patterns and improve targeting
  /career-ops offer-prep → Read a received offer/contract with the candidate: clause walk + lawyer questions (not legal advice)
  /career-ops titles    → Suggest adjacent job titles from your CV to broaden the search
  /career-ops upskill   → Aggregate skill-gap analysis from your evaluated reports
  /career-ops followup  → Follow-up cadence tracker: flag overdue, generate drafts
  /career-ops outcome   → Record application outcome & archive artifacts
  /career-ops update    → Update career-ops system files with diff preview + compat check

Inbox: add URLs to data/pipeline.md → /career-ops pipeline
Or paste a JD directly to run the full pipeline.

Context Loading by Mode

After determining the mode, load the necessary files before executing:

If modes/_custom.md exists, read it after modes/_profile.md and before the selected mode file. It contains user house rules and procedural preferences. It may override workflow/style defaults, but it never adds factual claims about the candidate.

Resolve language.modes_dir before applying the path shorthand below. With no setting, use modes. With a scalar directory, preserve the existing behavior: use that directory's _shared.md and localized mode file when it provides one. With a list, load every declared directory's _shared.md exactly once (including the baseline modes/_shared.md when modes appears), but use only the FIRST entry's evaluation-mode file for Blocks A-F; later entries contribute context, never a competing evaluation file. User-layer _profile.md and _custom.md remain under modes/.

Modes that require _shared.md + their mode file

Read the resolved shared context (default modes/_shared.md) + modes/_profile.md (if exists) + modes/_custom.md (if exists) + the resolved selected mode file (default modes/{mode}.md). For an A-F evaluation, that selected file is the primary directory's evaluation mode; do not also load an evaluation file from a secondary directory.

Applies to: auto-pipeline, oferta, ofertas, pdf, text, contacto, apply, pipeline, scan, batch

Standalone modes with profile and custom context

Read modes/_profile.md (if exists) + modes/_custom.md (if exists) + modes/{mode}.md

Applies to: tracker, agent-inbox, deep, interview-prep, interview, master-profile, regional/eu-swe, interview/plan, interview/practice, interview/debrief, latex, latex-tex, training, project, patterns, titles, upskill, followup, reply-watch, outcome, cover, email, add, offer-prep, discover

Modes delegated to subagent

For scan, apply (with Playwright), and pipeline (3+ URLs): launch as a worker/subagent with the resolved shared context + _profile.md (if exists) + _custom.md (if exists) + the resolved selected mode file injected into the worker prompt. If your CLI exposes an Agent(...) primitive, the call looks like this:

Agent(
  subagent_type="general-purpose",
  prompt="[output language directive]\n\n[content of modes/_shared.md, or resolved shared context: every declared _shared.md once]\n\n[content of modes/_profile.md if exists]\n\n[content of modes/_custom.md if exists]\n\n[content of modes/{mode}.md, or resolved selected mode file; primary evaluation file for Blocks A-F]\n\n[invocation-specific data]",
  description="career-ops {mode}"
)

Execute the instructions from the loaded mode file.

1---
2name: career-ops
3description: >-
4 AI job search command center -- evaluate offers, generate CVs, scan portals,
5 track applications. Use when the user pastes a job URL or JD, asks to scan
6 portals, generate a CV/PDF, track applications, prepare for interviews, draft
7 outreach/emails, or run any career-ops mode.
8arguments: mode
9user_invocable: true
10user-invocable: true
11argument-hint: "[scan | discover | deep | pdf | text | latex | latex-tex | cover | email | add | expand | eu-swe | oferta | ofertas | apply | batch | tracker | agent-inbox | pipeline | contacto | training | project | interview-prep | interview | master-profile | interview/plan | interview/practice | interview/debrief | interview-redflag | patterns | offer-prep | titles | upskill | followup | reply-watch | outcome | update]"
12license: MIT
13---
14 
15# career-ops -- Router
16 
17career-ops is a multi-CLI job-search command center. The routing below is shared across supported agent CLIs even when the invocation surface differs.
18 
19## Project Root Resolution
20 
21Before reading any repo-relative path, derive `PROJECT_ROOT` from this loaded `SKILL.md`: start at the skill file's directory and walk upward until the nearest directory containing both `AGENTS.md` and `modes/`. Resolve every path in this router (`modes/`, `config/`, `data/`, scripts, templates, and output paths) against `PROJECT_ROOT`, never against the process's current working directory. This is required even when the checkout itself is nested (for example `Development\\career-ops`) or the command starts from a subdirectory. If those two sentinels cannot be found, stop and locate the career-ops checkout before reading or writing files.
22 
23## Invocation Notes
24 
25- CLIs with slash-command registration can expose this router as `/career-ops`.
26- In Cursor, this skill lives at `.cursor/skills/career-ops/` and is auto-discovered; ask for a mode by name, or paste a JD/URL to trigger auto-pipeline.
27- In Pi, this skill is auto-discovered from `.agents/skills/career-ops/` and exposed as `/skill:career-ops`; `AGENTS.md` loads from the repo root as project context, so there is no wrapper file. Headless Pi workers use `pi -p "prompt"`. Project skill discovery follows Pi's per-folder trust decision: `/trust` applies to future Pi processes, so restart `pi` before invoking `/skill:career-ops` (`-a` trusts a single run and needs no restart).
28- Interactive Codex sessions use `codex` in the repo root. Slash commands are not guaranteed in Codex, so ask Codex to run the same mode by name if `/career-ops` is unavailable.
29- Headless Codex workers use `codex exec "prompt"`.
30- The routing semantics below stay the same regardless of whether the entrypoint is a slash command or a natural-language prompt.
31 
32Codex prompt examples that map to the same router semantics:
33 
34```text
35Evaluate this JD with career-ops auto-pipeline: https://company.com/jobs/123
36Run the career-ops scan mode and summarize new matches.
37Run the career-ops pipeline mode for data/pipeline.md.
38Run the career-ops pdf mode for the latest evaluated role.
39Run the career-ops tracker mode and summarize the current statuses.
40```
41 
42## Mode Routing
43 
44Determine the mode from `$mode`:
45 
46| Input | Mode |
47|-------|------|
48| (empty / no args) | `discovery` -- Show command menu |
49| JD text or URL (no sub-command) | **`auto-pipeline`** |
50| `oferta` | `oferta` |
51| `ofertas` | `ofertas` |
52| `contacto` | `contacto` |
53| `deep` | `deep` |
54| `interview-prep` | `interview-prep` |
55| `interview` | `interview` |
56| `master-profile` | `master-profile` |
57| `eu-swe` | `regional/eu-swe` |
58| `interview/plan` | `interview/plan` |
59| `interview/practice` | `interview/practice` |
60| `interview/debrief` | `interview/debrief` |
61| `pdf` | `pdf` |
62| `text` | `text` |
63| `latex` | `latex` |
64| `latex-tex` | `latex-tex` |
65| `email` | `email` |
66| `add` | `add` |
67| `expand` | `expand` |
68| `training` | `training` |
69| `project` | `project` |
70| `tracker` | `tracker` |
71| `agent-inbox` | `agent-inbox` |
72| `inbox` | `agent-inbox` |
73| `pipeline` | `pipeline` |
74| `apply` | `apply` |
75| `scan` | `scan` |
76| `discover` | `discover` |
77| `batch` | `batch` |
78| `patterns` | `patterns` |
79| `offer-prep` | `offer-prep` |
80| `titles` | `titles` |
81| `upskill` | `upskill` |
82| `followup` | `followup` |
83| `reply-watch` | `reply-watch` |
84| `outcome` | `outcome` |
85| `interview-redflag` | `interview-redflag` |
86| `update` | `update` |
87| `cover` | `cover` |
88 
89**Auto-pipeline detection:** If `$mode` is not a known sub-command AND contains JD text (keywords: "responsibilities", "requirements", "qualifications", "about the role", "we're looking for", company name + role) or a URL to a JD, execute `auto-pipeline`.
90 
91If `$mode` is not a sub-command AND doesn't look like a JD, show discovery.
92 
93---
94 
95## Output Language Directive
96 
97Before executing any mode, read `config/profile.yml` if it exists and resolve:
98 
99- `language.output` → ISO language code for human-facing output. Default: `en`.
100- `language.modes_dir` → optional market-mode directory. This controls market vocabulary and local evaluation rules only. It may be a single string (one declared market, the historical default) or a list of declared candidate markets for a candidate genuinely running parallel campaigns in more than one market at once (#3793), e.g. `modes_dir: [modes/de, modes/zh]`. When a list is given, the FIRST entry is primary and supplies the evaluation-mode file (Block A-F rules can only run from one market's file at a time); EVERY declared market's `_shared.md` is loaded into context. `modes` itself is a valid declared candidate for markets without a localized directory; when first it supplies `modes/oferta.md`, and its baseline `modes/_shared.md` is loaded once. Per posting, judge which declared market actually applies from the JD's own MARKET signals (hiring-entity jurisdiction, currency, benefits/legal vocabulary) — never from the JD's language alone. If genuinely ambiguous, an interactive session asks and stops before persistence; an unattended worker uses the primary market and records that fallback in the report header or Block G.
101 
102Inject this directive after loading the mode instructions and before producing any user-visible content:
103 
104> Write all human-facing output in `{language.output}` regardless of the language of these instructions or of the job description. This includes reports, tracker notes, PDFs, cover letters, outreach, interview prep, form answers, and summaries. If `language.modes_dir` supplies market-specific vocabulary (one market, or several declared at once), keep the market logic but explain terms in `{language.output}` when needed.
105 
106`language.output` is authoritative for prose. `modes_dir` is market context; it must not force the prose language.
107 
108---
109 
110## Discovery Mode (no arguments)
111 
112If your CLI supports `/career-ops`, show this menu. In Codex, surface the same options in plain text and map the requested mode the same way.
113 
114Concrete equivalents for Codex prompt-driven sessions:
115 
116```text
117/career-ops {JD} ↔ "Evaluate this JD with career-ops auto-pipeline: {JD or URL}"
118/career-ops scan ↔ "Run the career-ops scan mode and summarize new matches."
119/career-ops pipeline ↔ "Run the career-ops pipeline mode for data/pipeline.md."
120/career-ops pdf ↔ "Run the career-ops pdf mode for the latest evaluated role."
121/career-ops email ↔ "Run the career-ops email mode for the latest evaluated role."
122/career-ops tracker ↔ "Run the career-ops tracker mode and summarize the current statuses."
123```
124 
125Show this menu:
126 
127```
128career-ops -- Command Center
129 
130Available commands:
131 /career-ops {JD} → AUTO-PIPELINE: evaluate + report + PDF + tracker (paste text or URL)
132 /career-ops pipeline → Process pending URLs from inbox (data/pipeline.md)
133 /career-ops oferta → Evaluation only A-F (no auto PDF)
134 /career-ops ofertas → Compare and rank multiple offers
135 /career-ops contacto → LinkedIn power move: find contacts + draft message
136 /career-ops deep → Deep research prompt about company
137 /career-ops interview-prep → Generate company-specific interview prep doc
138 /career-ops interview → Interactive profile/CV onboarding interview
139 /career-ops master-profile → Import, review, and validate your Master Career Profile
140 /career-ops eu-swe → Calibrate a European SWE application before CV/apply/interview
141 /career-ops interview/plan → Time-blocked prep plan for an upcoming interview
142 /career-ops interview/practice → Practice interview, one question at a time with feedback
143 /career-ops interview/debrief → Post-interview debrief: close gaps, predict next round
144 /career-ops pdf → PDF only, ATS-optimized CV
145 /career-ops text → Tailored markdown CV (mirrors cv.md, no PDF)
146 /career-ops latex → Export CV as LaTeX/Overleaf .tex
147 /career-ops latex-tex → Tailor your own resume.tex in place (opt-in; cv.md stays default)
148 /career-ops cover → Cover letter: standalone JD paste or /career-ops cover {slug}
149 /career-ops email → Formal application email draft (draft-only; never sends, submits, or clicks)
150 /career-ops add → Add a project/paper/role to your CV (fetch + preview + confirm)
151 /career-ops expand → Auto-discover and add missing competencies from profile links
152 /career-ops training → Evaluate course/cert against North Star
153 /career-ops project → Evaluate portfolio project idea
154 /career-ops tracker → Application status overview
155 /career-ops agent-inbox → Queue/drain requests for the next session (data/agent-inbox.md)
156 /career-ops apply → Live application assistant (reads form + generates answers)
157 /career-ops scan → Scan portals and discover new offers
158 /career-ops discover → Resolve a company list to scannable ATS boards + append to portals.yml (zero-token)
159 /career-ops batch → Batch processing with parallel workers
160 /career-ops patterns → Analyze rejection patterns and improve targeting
161 /career-ops offer-prep → Read a received offer/contract with the candidate: clause walk + lawyer questions (not legal advice)
162 /career-ops titles → Suggest adjacent job titles from your CV to broaden the search
163 /career-ops upskill → Aggregate skill-gap analysis from your evaluated reports
164 /career-ops followup → Follow-up cadence tracker: flag overdue, generate drafts
165 /career-ops outcome → Record application outcome & archive artifacts
166 /career-ops update → Update career-ops system files with diff preview + compat check
167 
168Inbox: add URLs to data/pipeline.md → /career-ops pipeline
169Or paste a JD directly to run the full pipeline.
170```
171 
172---
173 
174## Context Loading by Mode
175 
176After determining the mode, load the necessary files before executing:
177 
178If `modes/_custom.md` exists, read it after `modes/_profile.md` and before the selected mode file. It contains user house rules and procedural preferences. It may override workflow/style defaults, but it never adds factual claims about the candidate.
179 
180Resolve `language.modes_dir` before applying the path shorthand below. With no setting, use `modes`. With a scalar directory, preserve the existing behavior: use that directory's `_shared.md` and localized mode file when it provides one. With a list, load every declared directory's `_shared.md` exactly once (including the baseline `modes/_shared.md` when `modes` appears), but use only the FIRST entry's evaluation-mode file for Blocks A-F; later entries contribute context, never a competing evaluation file. User-layer `_profile.md` and `_custom.md` remain under `modes/`.
181 
182### Modes that require `_shared.md` + their mode file
183 
184Read the resolved shared context (default `modes/_shared.md`) + `modes/_profile.md` (if exists) + `modes/_custom.md` (if exists) + the resolved selected mode file (default `modes/{mode}.md`). For an A-F evaluation, that selected file is the primary directory's evaluation mode; do not also load an evaluation file from a secondary directory.
185 
186Applies to: `auto-pipeline`, `oferta`, `ofertas`, `pdf`, `text`, `contacto`, `apply`, `pipeline`, `scan`, `batch`
187 
188### Standalone modes with profile and custom context
189 
190Read `modes/_profile.md` (if exists) + `modes/_custom.md` (if exists) + `modes/{mode}.md`
191 
192Applies to: `tracker`, `agent-inbox`, `deep`, `interview-prep`, `interview`, `master-profile`, `regional/eu-swe`, `interview/plan`, `interview/practice`, `interview/debrief`, `latex`, `latex-tex`, `training`, `project`, `patterns`, `titles`, `upskill`, `followup`, `reply-watch`, `outcome`, `cover`, `email`, `add`, `offer-prep`, `discover`
193 
194### Modes delegated to subagent
195 
196For `scan`, `apply` (with Playwright), and `pipeline` (3+ URLs): launch as a worker/subagent with the resolved shared context + `_profile.md` (if exists) + `_custom.md` (if exists) + the resolved selected mode file injected into the worker prompt. If your CLI exposes an `Agent(...)` primitive, the call looks like this:
197 
198```python
199Agent(
200 subagent_type="general-purpose",
201 prompt="[output language directive]\n\n[content of modes/_shared.md, or resolved shared context: every declared _shared.md once]\n\n[content of modes/_profile.md if exists]\n\n[content of modes/_custom.md if exists]\n\n[content of modes/{mode}.md, or resolved selected mode file; primary evaluation file for Blocks A-F]\n\n[invocation-specific data]",
202 description="career-ops {mode}"
203)
204```
205 
206Execute the instructions from the loaded mode file.
207 

Discussion