job-forge 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codex/config.toml +8 -0
- package/.cursor/mcp.json +21 -0
- package/.cursor/rules/main.mdc +519 -0
- package/.mcp.json +21 -0
- package/.opencode/agents/general-free.md +85 -0
- package/.opencode/agents/general-paid.md +39 -0
- package/.opencode/agents/glm-minimal.md +50 -0
- package/.opencode/skills/job-forge.md +185 -0
- package/AGENTS.md +514 -0
- package/CLAUDE.md +514 -0
- package/LICENSE +21 -0
- package/README.md +195 -0
- package/batch/README.md +60 -0
- package/batch/batch-prompt.md +399 -0
- package/batch/batch-runner.sh +673 -0
- package/bin/create-job-forge.mjs +375 -0
- package/bin/job-forge.mjs +120 -0
- package/bin/sync.mjs +141 -0
- package/config/profile.example.yml +67 -0
- package/cv-sync-check.mjs +128 -0
- package/dedup-tracker.mjs +201 -0
- package/docs/ARCHITECTURE.md +220 -0
- package/docs/CUSTOMIZATION.md +101 -0
- package/docs/MODEL-ROUTING.md +195 -0
- package/docs/README.md +54 -0
- package/docs/SETUP.md +186 -0
- package/docs/demo.gif +0 -0
- package/fonts/dm-sans-latin-ext.woff2 +0 -0
- package/fonts/dm-sans-latin.woff2 +0 -0
- package/fonts/space-grotesk-latin-ext.woff2 +0 -0
- package/fonts/space-grotesk-latin.woff2 +0 -0
- package/generate-pdf.mjs +168 -0
- package/iso/agents/general-free.md +90 -0
- package/iso/agents/general-paid.md +44 -0
- package/iso/agents/glm-minimal.md +55 -0
- package/iso/commands/job-forge.md +188 -0
- package/iso/config.json +7 -0
- package/iso/instructions.md +514 -0
- package/iso/mcp.json +15 -0
- package/merge-tracker.mjs +377 -0
- package/modes/README.md +30 -0
- package/modes/_shared-calibration.md +26 -0
- package/modes/_shared.md +272 -0
- package/modes/apply.md +257 -0
- package/modes/auto-pipeline.md +70 -0
- package/modes/batch.md +110 -0
- package/modes/compare.md +23 -0
- package/modes/contact.md +82 -0
- package/modes/deep.md +99 -0
- package/modes/followup.md +68 -0
- package/modes/negotiation.md +146 -0
- package/modes/offer.md +199 -0
- package/modes/pdf.md +121 -0
- package/modes/pipeline.md +83 -0
- package/modes/project.md +30 -0
- package/modes/rejection.md +92 -0
- package/modes/scan.md +185 -0
- package/modes/tracker.md +31 -0
- package/modes/training.md +27 -0
- package/normalize-statuses.mjs +152 -0
- package/opencode.json +28 -0
- package/package.json +78 -0
- package/scripts/add-tags.mjs +894 -0
- package/scripts/cursor-agent-loop.sh +211 -0
- package/scripts/cursor-agent-stream-format.py +134 -0
- package/scripts/next-num.mjs +33 -0
- package/scripts/release/check-source.mjs +37 -0
- package/scripts/render-report-header.mjs +78 -0
- package/scripts/session-report.mjs +129 -0
- package/scripts/slugify.mjs +27 -0
- package/scripts/today.mjs +20 -0
- package/scripts/token-usage-report.mjs +315 -0
- package/scripts/tracker-line.mjs +67 -0
- package/scripts/verify-greenhouse-urls.mjs +195 -0
- package/templates/cv-template.html +395 -0
- package/templates/portals.example.yml +3140 -0
- package/templates/states.yml +62 -0
- package/tracker-lib.mjs +257 -0
- package/verify-pipeline.mjs +267 -0
package/README.md
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# JobForge
|
|
2
|
+
|
|
3
|
+
> AI-powered job search pipeline built on opencode. Evaluate offers, generate tailored CVs, scan portals, negotiate offers, and track everything -- powered by AI agents.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<img src="demo/demo.gif" alt="JobForge Demo" width="800">
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<p align="center"><em>Paste a job URL. Get a scored evaluation, tailored CV, and tracked application — in seconds.</em></p>
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx github:razroo/JobForge create-job-forge my-job-search
|
|
23
|
+
cd my-job-search
|
|
24
|
+
npm install
|
|
25
|
+
opencode
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The scaffolded `opencode.json` already has the Geometra MCP (browser automation + PDF) and Gmail MCP (reading replies) wired up — they launch automatically the first time opencode starts.
|
|
29
|
+
|
|
30
|
+
Then fill in `cv.md`, `config/profile.yml`, and `portals.yml` with your personal data, paste a job URL into opencode, and JobForge evaluates + tracks it.
|
|
31
|
+
|
|
32
|
+
**Upgrade later:** `npm run update-harness` (pulls latest harness + fallback plugin, re-syncs symlinks, prints the resolved commit)
|
|
33
|
+
|
|
34
|
+
Full setup guide and alternative install paths (including contributing to the harness itself): **[docs/SETUP.md](docs/SETUP.md)**.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## What Is This
|
|
39
|
+
|
|
40
|
+
JobForge turns opencode into a full job search command center. Instead of manually tracking applications in a spreadsheet, you get an AI-powered pipeline that:
|
|
41
|
+
|
|
42
|
+
- **Evaluates offers** with a unified 10-dimension weighted scoring system
|
|
43
|
+
- **Generates tailored PDFs** -- ATS-optimized CVs with anti-AI-detection writing rules
|
|
44
|
+
- **Scans portals** with fuzzy dedup (catches reposts with new URLs)
|
|
45
|
+
- **Processes in batch** -- evaluate 10+ offers in parallel with sub-agents
|
|
46
|
+
- **Tracks everything** with pipeline integrity checks and canonical state management
|
|
47
|
+
- **Manages follow-ups** -- timing-based nudges so you never miss a window
|
|
48
|
+
- **Learns from rejections** -- pattern analysis across all rejections by stage, archetype, and score
|
|
49
|
+
- **Negotiates offers** -- structured comp breakdown, leverage assessment, counter-offer strategy
|
|
50
|
+
|
|
51
|
+
> **Important: This is NOT a spray-and-pray tool.** The whole point is to apply only where there's a real match. The scoring system helps you focus on high-fit opportunities instead of wasting everyone's time. Always review before submitting.
|
|
52
|
+
|
|
53
|
+
## Features
|
|
54
|
+
|
|
55
|
+
| Feature | Description |
|
|
56
|
+
|---------|-------------|
|
|
57
|
+
| **Auto-Pipeline** | Paste a URL, get a full evaluation + PDF + tracker entry |
|
|
58
|
+
| **Unified Scoring** | 10 weighted dimensions, consistent across all modes, with calibration anchors |
|
|
59
|
+
| **Anti-AI-Detection CVs** | Writing rules that avoid ATS filters on Indeed, LinkedIn, Workday |
|
|
60
|
+
| **6-Block Evaluation** | Role summary, CV match, level strategy, comp research, personalization, interview prep (STAR+R) |
|
|
61
|
+
| **Interview Story Bank** | Curated bank of 10-12 stories with match counts, archetype tags, and automatic pruning |
|
|
62
|
+
| **Follow-Up System** | Timing-based nudges: Applied 7+ days ago nudge, Interviewed 1 day ago thank-you note, email scanning via Gmail MCP |
|
|
63
|
+
| **Gmail Integration** | MCP server configured to retrieve emails for interview callbacks, offer responses, and application status updates |
|
|
64
|
+
| **Rejection Analysis** | Captures stage + reason, surfaces patterns (archetype gaps, scoring miscalibration) |
|
|
65
|
+
| **Offer Negotiation** | Total comp breakdown, equity valuation, leverage from pipeline, counter-offer scripts |
|
|
66
|
+
| **Deep Research** | Company research that feeds back into scores and interview prep |
|
|
67
|
+
| **Smart LinkedIn Outreach** | Reads evaluation reports to craft targeted messages using top proof points |
|
|
68
|
+
| **Portal Scanner** | 45+ companies pre-configured with fuzzy dedup for reposts |
|
|
69
|
+
| **Batch Processing** | Parallel evaluation with `opencode run` workers, with honest verification flagging |
|
|
70
|
+
| **Pipeline Integrity** | Automated merge, dedup, status normalization, health checks |
|
|
71
|
+
| **Cost-Aware Agent Routing** | Three subagents (`@general-free`, `@general-paid`, `@glm-minimal`) with per-task model tiers; procedural work runs on free-tier models, quality-sensitive work on paid. See [Subagent Routing in AGENTS.md](AGENTS.md) for the task-to-agent mapping. |
|
|
72
|
+
| **Automatic Model Fallback** | When a model rate-limits or 5xx's, [`@razroo/opencode-model-fallback`](https://www.npmjs.com/package/@razroo/opencode-model-fallback) rotates the agent through a configured `fallback_models` chain and replays the request. Ships with sensible defaults: free-tier agents fall back to another free model then to paid as an escape hatch, paid agents fall back to a different paid provider. |
|
|
73
|
+
| **Token Cost Visibility** | `job-forge tokens --days 1` for per-session breakdown; `job-forge session-report --since-minutes 60 --log` to flag sessions over budget and append history to `data/token-usage.tsv`. Auto-logged after every batch run. |
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
/job-forge → Show all available commands
|
|
79
|
+
/job-forge {paste a JD} → Full auto-pipeline (evaluate + PDF + tracker)
|
|
80
|
+
/job-forge scan → Scan portals for new offers
|
|
81
|
+
/job-forge pdf → Generate ATS-optimized CV
|
|
82
|
+
/job-forge batch → Batch evaluate multiple offers
|
|
83
|
+
/job-forge tracker → View application status
|
|
84
|
+
/job-forge apply → Fill application forms with AI
|
|
85
|
+
/job-forge pipeline → Process pending URLs
|
|
86
|
+
/job-forge contact → LinkedIn outreach (uses evaluation report)
|
|
87
|
+
/job-forge deep → Deep company research (feeds back into scores)
|
|
88
|
+
/job-forge followup → Check what needs follow-up action
|
|
89
|
+
/job-forge rejection → Record/analyze rejection patterns
|
|
90
|
+
/job-forge negotiation → Structured offer negotiation
|
|
91
|
+
/job-forge training → Evaluate a course/cert
|
|
92
|
+
/job-forge project → Evaluate a portfolio project
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Or just paste a job URL or description directly -- JobForge auto-detects it and runs the full pipeline.
|
|
96
|
+
|
|
97
|
+
> **The system is designed to be customized by opencode itself.** Modes, archetypes, scoring weights, negotiation scripts -- just ask opencode to change them: "Change the archetypes to backend engineering roles", "Add these 5 companies to portals.yml", "Update my profile with this CV I'm pasting".
|
|
98
|
+
|
|
99
|
+
## How It Works
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
You paste a job URL or description
|
|
103
|
+
│
|
|
104
|
+
▼
|
|
105
|
+
┌──────────────────┐
|
|
106
|
+
│ Archetype │ Classifies: LLMOps / Agentic / PM / SA / FDE / Transformation
|
|
107
|
+
│ Detection │
|
|
108
|
+
└────────┬─────────┘
|
|
109
|
+
│
|
|
110
|
+
┌────────▼─────────┐
|
|
111
|
+
│ A-F Evaluation │ Match, gaps, comp research, STAR stories
|
|
112
|
+
│ (reads cv.md) │ Unified 10-dimension scoring model
|
|
113
|
+
└────────┬─────────┘
|
|
114
|
+
│
|
|
115
|
+
┌────┼────┐
|
|
116
|
+
▼ ▼ ▼
|
|
117
|
+
Report PDF Tracker
|
|
118
|
+
.md .pdf .tsv
|
|
119
|
+
│
|
|
120
|
+
┌────┼────┐
|
|
121
|
+
▼ ▼ ▼
|
|
122
|
+
Apply Follow Negotiate
|
|
123
|
+
up (if offer)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Project Structure
|
|
127
|
+
|
|
128
|
+
**Your personal project** (after `npx create-job-forge my-search`):
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
my-search/
|
|
132
|
+
├── package.json # depends on "job-forge" (github:razroo/JobForge)
|
|
133
|
+
├── opencode.json # thin config — enables MCPs + states.yml
|
|
134
|
+
├── cv.md # your CV (personal)
|
|
135
|
+
├── article-digest.md # your proof points (optional, personal)
|
|
136
|
+
├── portals.yml # companies you want to scan (personal)
|
|
137
|
+
├── config/profile.yml # your identity, target roles (personal)
|
|
138
|
+
├── data/ # applications, pipeline, scan history (personal, gitignored)
|
|
139
|
+
├── reports/ # generated evaluation reports (personal, gitignored)
|
|
140
|
+
├── batch/
|
|
141
|
+
│ ├── batch-input.tsv # URLs to batch-evaluate (personal)
|
|
142
|
+
│ ├── batch-state.tsv # resumable batch state (personal)
|
|
143
|
+
│ ├── tracker-additions/ # TSVs waiting to merge (personal)
|
|
144
|
+
│ ├── logs/ # per-worker logs (personal, gitignored)
|
|
145
|
+
│ ├── batch-prompt.md # → symlink to node_modules/job-forge/
|
|
146
|
+
│ └── batch-runner.sh # → symlink to node_modules/job-forge/
|
|
147
|
+
├── modes/ # → symlink to node_modules/job-forge/modes/
|
|
148
|
+
├── templates/ # → symlink to node_modules/job-forge/templates/
|
|
149
|
+
├── .opencode/skills/job-forge.md # → symlink to node_modules/job-forge/
|
|
150
|
+
└── node_modules/job-forge/ # the harness (fetched from github:razroo/JobForge)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Symlinks are regenerated on every `npm install` via the package's `postinstall` hook. You never have to know about harness internals — just edit `cv.md`, `portals.yml`, and `config/profile.yml`.
|
|
154
|
+
|
|
155
|
+
**The harness itself** (this repo, what gets installed into `node_modules/job-forge/`):
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
JobForge/
|
|
159
|
+
├── package.json # bin: job-forge, create-job-forge
|
|
160
|
+
├── bin/
|
|
161
|
+
│ ├── job-forge.mjs # CLI dispatcher (merge/verify/pdf/tokens/sync/...)
|
|
162
|
+
│ ├── sync.mjs # postinstall: creates symlinks in consumer project
|
|
163
|
+
│ └── create-job-forge.mjs # npx create-job-forge scaffolder
|
|
164
|
+
├── .opencode/skills/job-forge.md # the skill router
|
|
165
|
+
├── modes/ # _shared.md + 16 skill modes
|
|
166
|
+
├── templates/ # cv-template.html, portals.example.yml, states.yml
|
|
167
|
+
├── config/profile.example.yml # template for consumer's profile.yml
|
|
168
|
+
├── batch/batch-prompt.md # batch worker prompt template
|
|
169
|
+
├── batch/batch-runner.sh # parallel orchestrator
|
|
170
|
+
├── scripts/token-usage-report.mjs # opencode cost analyzer
|
|
171
|
+
├── tracker-lib.mjs # shared tracker read/write helper
|
|
172
|
+
├── merge-tracker.mjs # merge batch TSVs → tracker
|
|
173
|
+
├── dedup-tracker.mjs # remove dupes
|
|
174
|
+
├── verify-pipeline.mjs # pipeline integrity checks
|
|
175
|
+
├── normalize-statuses.mjs # canonicalize status values
|
|
176
|
+
├── generate-pdf.mjs # CV PDF generator
|
|
177
|
+
├── cv-sync-check.mjs # setup lint
|
|
178
|
+
├── dashboard/ # optional Go TUI
|
|
179
|
+
├── fonts/ # Space Grotesk + DM Sans (for PDF)
|
|
180
|
+
└── docs/ # architecture, setup, customization
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Documentation
|
|
184
|
+
|
|
185
|
+
Index and cross-links: [docs/README.md](docs/README.md).
|
|
186
|
+
|
|
187
|
+
- [Setup](docs/SETUP.md) — both install paths, profile, CV, portals, verify, token tracking, troubleshooting
|
|
188
|
+
- [Architecture](docs/ARCHITECTURE.md) — package architecture, modes, evaluation flow, batch runner, pipeline scripts
|
|
189
|
+
- [Customization](docs/CUSTOMIZATION.md) — archetypes, scanner keywords, CV template, states, customizing symlinked modes
|
|
190
|
+
- [Model Routing](docs/MODEL-ROUTING.md) — the three cost-tiered subagents, why the architecture exists, and how to swap models or add your own
|
|
191
|
+
- [Contributing](CONTRIBUTING.md) — branch workflow, quality gate, and ideas for PRs
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
MIT
|
package/batch/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Batch evaluation
|
|
2
|
+
|
|
3
|
+
The `batch/` folder holds the **parallel batch runner** for processing 10+ job URLs with headless `opencode run` workers. For how batch fits into the rest of JobForge, see [docs/ARCHITECTURE.md](../docs/ARCHITECTURE.md).
|
|
4
|
+
|
|
5
|
+
## What ships in git
|
|
6
|
+
|
|
7
|
+
| Path | Role |
|
|
8
|
+
|------|------|
|
|
9
|
+
| `batch-runner.sh` | Orchestrator: parallelism, state, retries, resume |
|
|
10
|
+
| `batch-prompt.md` | Prompt template passed to each worker (keep evaluation and scoring instructions aligned with the canonical model in [`modes/_shared.md`](../modes/_shared.md) so batch scores match single-offer runs) |
|
|
11
|
+
| `README.md` | This file |
|
|
12
|
+
|
|
13
|
+
## Local-only files (gitignored when present)
|
|
14
|
+
|
|
15
|
+
Per [`.gitignore`](../.gitignore): `batch-input.tsv`, `batch-state.tsv`, `logs/*`, and `tracker-additions/*.tsv`. Empty dirs (`logs/`, `tracker-additions/`) use `.gitkeep` so the tree exists in a fresh clone.
|
|
16
|
+
|
|
17
|
+
## Input: `batch-input.tsv`
|
|
18
|
+
|
|
19
|
+
Tab-separated UTF-8 text, with a **header row** (the runner skips the literal `id` header):
|
|
20
|
+
|
|
21
|
+
| Column | Required | Description |
|
|
22
|
+
|--------|----------|-------------|
|
|
23
|
+
| `id` | Yes | Numeric offer id (used for state and ordering) |
|
|
24
|
+
| `url` | Yes | Job posting URL |
|
|
25
|
+
| `source` | No | Short label (e.g. board or company) |
|
|
26
|
+
| `notes` | No | Free text for your own context |
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
id url source notes
|
|
32
|
+
1 https://jobs.example.com/123 greenhouse Staff engineer
|
|
33
|
+
2 https://boards.example.com/456 ashby Remote OK
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Create this file in **`batch/`** next to the runner (see `batch-runner.sh` constants). Then:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
./batch/batch-runner.sh --dry-run # from repo root
|
|
40
|
+
./batch/batch-runner.sh
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Options and file layout: `./batch/batch-runner.sh --help`.
|
|
44
|
+
|
|
45
|
+
## After a batch run
|
|
46
|
+
|
|
47
|
+
Workers write one-line TSV rows under `batch/tracker-additions/`. Merge them into your tracker from the repo root:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm run merge
|
|
51
|
+
npm run verify # optional: pipeline health after merge (report links, statuses, pending TSVs)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
(`node merge-tracker.mjs` — same as `npm run merge`; see [CONTRIBUTING.md](../CONTRIBUTING.md#development).)
|
|
55
|
+
|
|
56
|
+
After a successful merge, each processed file is moved to **`batch/tracker-additions/merged/`** (created on first merge when the directory does not yet exist). `npm run verify` only looks for `*.tsv` files in the **top level** of `batch/tracker-additions/`, so rows already merged and archived under `merged/` do not trigger the “pending TSVs” warning.
|
|
57
|
+
|
|
58
|
+
## Prerequisites
|
|
59
|
+
|
|
60
|
+
The runner expects the `opencode` CLI on `PATH` and a valid `batch-prompt.md`. It creates `reports/` and tracker paths when they do not exist; ensure your usual JobForge setup (`cv.md`, `config/profile.yml`, `portals.yml`) matches what `batch-prompt.md` assumes.
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
# job-forge Batch Worker — Full Evaluation + PDF + Tracker Line
|
|
2
|
+
|
|
3
|
+
You are a job offer evaluation worker for the candidate (read name from config/profile.yml). You may receive either a **single offer** or a **bundle of offers** (the orchestrator chooses based on `--bundle-size`). For each offer you produce:
|
|
4
|
+
|
|
5
|
+
1. Full A-F evaluation (report .md)
|
|
6
|
+
2. Personalized ATS-optimized PDF
|
|
7
|
+
3. Tracker line for later merge
|
|
8
|
+
|
|
9
|
+
## Bundled mode (when the user message contains a JSON array of offers)
|
|
10
|
+
|
|
11
|
+
If the user message carries an `Offers: [ ... ]` JSON array, process each offer **fully and sequentially** — do not interleave steps across offers. For each offer in order:
|
|
12
|
+
|
|
13
|
+
1. Run the full pipeline below (Steps 1-6) using its `id`, `url`, `jd_file`, `report_num`, `date`.
|
|
14
|
+
2. After finishing that offer, emit **exactly one single-line JSON status** to stdout with this shape:
|
|
15
|
+
```
|
|
16
|
+
{"id":"<id>","status":"completed|failed","report_num":"<num>","company":"...","role":"...","score":<num-or-null>,"pdf":"<path-or-null>","report":"<path-or-null>","error":"<msg-or-null>"}
|
|
17
|
+
```
|
|
18
|
+
3. Move to the next offer. **Do NOT stop the bundle if one offer fails** — mark it failed and continue.
|
|
19
|
+
4. The orchestrator (`batch-runner.sh`) parses these status lines to update `batch-state.tsv`. Missing status = worker didn't reach that offer = counts as failed.
|
|
20
|
+
|
|
21
|
+
## Single-offer mode (legacy, when no Offers array)
|
|
22
|
+
|
|
23
|
+
Read `{{URL}}`, `{{JD_FILE}}`, `{{REPORT_NUM}}`, `{{DATE}}`, `{{ID}}` from the user message and run the pipeline once. Emit the same single-line status JSON at the end.
|
|
24
|
+
|
|
25
|
+
**IMPORTANT**: This prompt is self-contained. You have EVERYTHING you need here. You do not depend on any other skill or system.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Sources of Truth (READ before evaluating)
|
|
30
|
+
|
|
31
|
+
| File | Absolute path | When |
|
|
32
|
+
|------|---------------|------|
|
|
33
|
+
| cv.md | `cv.md (project root)` | ALWAYS |
|
|
34
|
+
| llms.txt | `llms.txt (if exists)` | ALWAYS |
|
|
35
|
+
| article-digest.md | `article-digest.md (project root)` | ALWAYS (proof points) |
|
|
36
|
+
| i18n.ts | `i18n.ts (if exists, optional)` | Only for interviews/deep |
|
|
37
|
+
| cv-template.html | `templates/cv-template.html` | For PDF |
|
|
38
|
+
| generate-pdf.mjs | `generate-pdf.mjs` | For PDF |
|
|
39
|
+
|
|
40
|
+
**RULE: NEVER write to cv.md or i18n.ts.** They are read-only.
|
|
41
|
+
**RULE: NEVER hardcode metrics.** Read them from cv.md + article-digest.md at evaluation time.
|
|
42
|
+
**RULE: For article metrics, article-digest.md takes precedence over cv.md.** cv.md may have older numbers — that's normal.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Job-Specific Parameters (read from user message)
|
|
47
|
+
|
|
48
|
+
The orchestrator passes the concrete values for this job **in the user message**, not in this prompt. This prompt is a static template shared across all workers so the opencode prompt cache can be reused — resolving per-job values here would bust the cache on every run.
|
|
49
|
+
|
|
50
|
+
Look in the user message for:
|
|
51
|
+
|
|
52
|
+
| Parameter | Description |
|
|
53
|
+
|-----------|-------------|
|
|
54
|
+
| URL | Offer URL |
|
|
55
|
+
| JD file | Path to the file containing the JD text |
|
|
56
|
+
| Report number | 3 digits, zero-padded (001, 002...) |
|
|
57
|
+
| Date | YYYY-MM-DD |
|
|
58
|
+
| Batch ID | Unique offer ID from batch-input.tsv |
|
|
59
|
+
|
|
60
|
+
Everywhere this prompt writes `{{URL}}`, `{{JD_FILE}}`, `{{REPORT_NUM}}`, `{{DATE}}`, `{{ID}}`, substitute the values from the user message.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Pipeline (execute in order)
|
|
65
|
+
|
|
66
|
+
### Step 1 — Retrieve JD
|
|
67
|
+
|
|
68
|
+
**Note: Batch workers do NOT have Geometra MCP/browser access.** Use WebFetch only, and fetch each URL at most once.
|
|
69
|
+
|
|
70
|
+
1. Read the JD file at `{{JD_FILE}}` (provided by orchestrator)
|
|
71
|
+
2. If the JD file has content, use it directly — do NOT also WebFetch the URL (the file is the source of truth)
|
|
72
|
+
3. If the JD file is empty or missing, WebFetch `{{URL}}` **once**
|
|
73
|
+
4. If WebFetch returns content but it looks like a shell page (no JD text, just navbar/footer), add `**Verification: unconfirmed**` to the report header and proceed — the conductor or user will verify later
|
|
74
|
+
5. If both the file and WebFetch fail, report an error and stop
|
|
75
|
+
|
|
76
|
+
**Never chain WebFetch + file read + second WebFetch for the same URL** — each fetch re-pulls the same tokens into context.
|
|
77
|
+
|
|
78
|
+
### Step 2 — A-F Evaluation
|
|
79
|
+
|
|
80
|
+
`cv.md` is already in your context via `opencode.json:instructions` — use it directly, do NOT Read it again. Execute ALL blocks:
|
|
81
|
+
|
|
82
|
+
#### Step 0 — Archetype Detection
|
|
83
|
+
|
|
84
|
+
Classify the offer into one of the 6 archetypes. If it's a hybrid, indicate the 2 closest ones.
|
|
85
|
+
|
|
86
|
+
**The 6 archetypes (all equally valid):**
|
|
87
|
+
|
|
88
|
+
| Archetype | Key themes | What they're buying |
|
|
89
|
+
|-----------|------------|---------------------|
|
|
90
|
+
| **AI Platform / LLMOps Engineer** | Evaluation, observability, reliability, pipelines | Someone who puts AI into production with metrics |
|
|
91
|
+
| **Agentic Workflows / Automation** | HITL, tooling, orchestration, multi-agent | Someone who builds reliable agent systems |
|
|
92
|
+
| **Technical AI Product Manager** | GenAI/Agents, PRDs, discovery, delivery | Someone who translates business → AI product |
|
|
93
|
+
| **AI Solutions Architect** | Hyperautomation, enterprise, integrations | Someone who designs end-to-end AI architectures |
|
|
94
|
+
| **AI Forward Deployed Engineer** | Client-facing, fast delivery, prototyping | Someone who delivers AI solutions to clients fast |
|
|
95
|
+
| **AI Transformation Lead** | Change management, adoption, org enablement | Someone who leads AI transformation in an organization |
|
|
96
|
+
|
|
97
|
+
**Adaptive framing:**
|
|
98
|
+
|
|
99
|
+
> **Concrete metrics are read from `cv.md` + `article-digest.md` at each evaluation. NEVER hardcode numbers here.**
|
|
100
|
+
|
|
101
|
+
| If the role is... | Emphasize about the candidate... | Proof point sources |
|
|
102
|
+
|-------------------|--------------------------|--------------------------|
|
|
103
|
+
| Platform / LLMOps | Production systems builder, observability, evals, closed-loop | article-digest.md + cv.md |
|
|
104
|
+
| Agentic / Automation | Multi-agent orchestration, HITL, reliability, cost | article-digest.md + cv.md |
|
|
105
|
+
| Technical AI PM | Product discovery, PRDs, metrics, stakeholder mgmt | cv.md + article-digest.md |
|
|
106
|
+
| Solutions Architect | System design, integrations, enterprise-ready | article-digest.md + cv.md |
|
|
107
|
+
| Forward Deployed Engineer | Fast delivery, client-facing, prototype → prod | cv.md + article-digest.md |
|
|
108
|
+
| AI Transformation Lead | Change management, team enablement, adoption | cv.md + article-digest.md |
|
|
109
|
+
|
|
110
|
+
**Cross-cutting advantage**: Frame the candidate's profile as a **"Technical builder"** who adapts their framing to the role.
|
|
111
|
+
|
|
112
|
+
- For PM: "builder who reduces uncertainty with prototypes and then productionizes with discipline".
|
|
113
|
+
- For FDE: "builder who delivers fast with observability and metrics from day 1".
|
|
114
|
+
- For SA: "builder who designs end-to-end systems with real integration experience".
|
|
115
|
+
- For LLMOps: "builder who puts AI into production with closed-loop quality systems — read metrics from article-digest.md".
|
|
116
|
+
|
|
117
|
+
Turn "builder" into a professional signal, not a "hobby maker" label. The framing changes, the truth stays the same.
|
|
118
|
+
|
|
119
|
+
#### Block A — Role Summary
|
|
120
|
+
|
|
121
|
+
Table with: Detected archetype, Domain, Function, Seniority, Remote, Team size, TL;DR.
|
|
122
|
+
|
|
123
|
+
#### Block B — CV Match
|
|
124
|
+
|
|
125
|
+
`cv.md` is already in context (via `instructions`) — use it directly, do NOT Read it again. Table with each JD requirement mapped to exact CV lines or i18n.ts keys.
|
|
126
|
+
|
|
127
|
+
**Adapted to archetype:**
|
|
128
|
+
|
|
129
|
+
- FDE → prioritize fast delivery and client-facing.
|
|
130
|
+
- SA → prioritize system design and integrations.
|
|
131
|
+
- PM → prioritize product discovery and metrics.
|
|
132
|
+
- LLMOps → prioritize evals, observability, pipelines.
|
|
133
|
+
- Agentic → prioritize multi-agent, HITL, orchestration.
|
|
134
|
+
- Transformation → prioritize change management, adoption, scaling.
|
|
135
|
+
|
|
136
|
+
**Gaps** section with mitigation strategy for each one:
|
|
137
|
+
1. Is it a hard blocker or a preference-only requirement?
|
|
138
|
+
2. Can the candidate demonstrate adjacent experience?
|
|
139
|
+
3. Is there a portfolio project that covers this gap?
|
|
140
|
+
4. Concrete mitigation plan
|
|
141
|
+
|
|
142
|
+
#### Block C — Level and Strategy
|
|
143
|
+
|
|
144
|
+
1. **Detected level** in the JD vs **candidate's current level** (staff / senior / mid, based on title history in cv.md)
|
|
145
|
+
2. **"Sell senior without lying" plan**: specific phrases, concrete achievements, founder experience as an advantage
|
|
146
|
+
3. **"If I get downleveled" plan**: accept if comp is fair, 6-month review, clear criteria
|
|
147
|
+
|
|
148
|
+
#### Block D — Comp and Demand
|
|
149
|
+
|
|
150
|
+
Use WebSearch for current salaries (Glassdoor, Levels.fyi, Blind), company comp reputation, demand trends. Table with data and cited sources. If no data available, say so.
|
|
151
|
+
|
|
152
|
+
Comp score (1-5): 5=top quartile, 4=above market, 3=median, 2=slightly below, 1=well below.
|
|
153
|
+
|
|
154
|
+
#### Block E — Personalization Plan
|
|
155
|
+
|
|
156
|
+
| # | Section | Current state | Proposed change | Why |
|
|
157
|
+
|---|---------|---------------|-----------------|-----|
|
|
158
|
+
|
|
159
|
+
Top 5 CV changes + Top 5 LinkedIn changes.
|
|
160
|
+
|
|
161
|
+
#### Block F — Interview Plan
|
|
162
|
+
|
|
163
|
+
6-10 STAR stories mapped to JD requirements:
|
|
164
|
+
|
|
165
|
+
| # | JD Requirement | STAR Story | S | T | A | R |
|
|
166
|
+
|
|
167
|
+
**Selection adapted to archetype.** Also include:
|
|
168
|
+
- 1 recommended case study (which project to present and how)
|
|
169
|
+
- Red-flag questions and how to answer them
|
|
170
|
+
|
|
171
|
+
#### Global Score
|
|
172
|
+
|
|
173
|
+
**Use the Canonical Scoring Model from `modes/_shared.md`.** All 10 dimensions, weighted exactly as defined there. This ensures scores from batch workers are directly comparable to scores from interactive evaluations and the `compare` comparison mode.
|
|
174
|
+
|
|
175
|
+
**Emit the score as a single JSON block** per `_shared.md` → "Score Emission — EMIT-ONCE JSON". Do NOT also write a prose scoring table — the JSON is the only representation. The report `.md` embeds this JSON verbatim under a `## Score` section, and Blocks A-F reference it by key instead of re-enumerating the 10 dimensions.
|
|
176
|
+
|
|
177
|
+
### Step 3 — Save Report .md
|
|
178
|
+
|
|
179
|
+
Save the full evaluation to:
|
|
180
|
+
```
|
|
181
|
+
reports/{{REPORT_NUM}}-{company-slug}-{{DATE}}.md
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Where `{company-slug}` is the company name in lowercase, no spaces, with hyphens.
|
|
185
|
+
|
|
186
|
+
**Report format:**
|
|
187
|
+
|
|
188
|
+
```markdown
|
|
189
|
+
# Evaluation: {Company} — {Role}
|
|
190
|
+
|
|
191
|
+
**Date:** {{DATE}}
|
|
192
|
+
**Archetype:** {detected}
|
|
193
|
+
**Score:** {X.X/5}
|
|
194
|
+
**URL:** {original offer URL}
|
|
195
|
+
**PDF:** job-forge/output/cv-candidate-{company-slug}-{{DATE}}.pdf
|
|
196
|
+
**Batch ID:** {{ID}}
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Score
|
|
201
|
+
|
|
202
|
+
{the Score JSON block from _shared.md, verbatim, inside a fenced ```json block}
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## A) Role Summary
|
|
207
|
+
(full content — reference scores by key, do not re-enumerate the 10 dimensions)
|
|
208
|
+
|
|
209
|
+
## B) CV Match
|
|
210
|
+
(full content)
|
|
211
|
+
|
|
212
|
+
## C) Level and Strategy
|
|
213
|
+
(full content)
|
|
214
|
+
|
|
215
|
+
## D) Comp and Demand
|
|
216
|
+
(full content)
|
|
217
|
+
|
|
218
|
+
## E) Personalization Plan
|
|
219
|
+
(full content)
|
|
220
|
+
|
|
221
|
+
## F) Interview Plan
|
|
222
|
+
(full content)
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Extracted Keywords
|
|
227
|
+
(15-20 JD keywords for ATS)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Step 4 — Generate PDF
|
|
231
|
+
|
|
232
|
+
1. Read `cv.md` + `i18n.ts`
|
|
233
|
+
2. Extract 15-20 keywords from the JD
|
|
234
|
+
3. Detect JD language → CV language (EN default)
|
|
235
|
+
4. Detect company location → paper format: US/Canada → `letter`, rest → `a4`
|
|
236
|
+
5. Detect archetype → adapt framing
|
|
237
|
+
6. Rewrite Professional Summary injecting keywords
|
|
238
|
+
7. Select top 3-4 most relevant projects
|
|
239
|
+
8. Reorder experience bullets by relevance to JD
|
|
240
|
+
9. Build competency grid (6-8 keyword phrases)
|
|
241
|
+
10. Inject keywords into existing achievements (**NEVER fabricate**)
|
|
242
|
+
11. Generate full HTML from template (read `templates/cv-template.html`)
|
|
243
|
+
12. Write HTML to `/tmp/cv-candidate-{company-slug}.html`
|
|
244
|
+
13. Run:
|
|
245
|
+
```bash
|
|
246
|
+
node generate-pdf.mjs \
|
|
247
|
+
/tmp/cv-candidate-{company-slug}.html \
|
|
248
|
+
output/cv-candidate-{company-slug}-{{DATE}}.pdf \
|
|
249
|
+
--format={letter|a4}
|
|
250
|
+
```
|
|
251
|
+
14. Report: PDF path, page count, keyword coverage %
|
|
252
|
+
|
|
253
|
+
**ATS rules:**
|
|
254
|
+
- Single-column (no sidebars)
|
|
255
|
+
- Standard headers: "Professional Summary", "Work Experience", "Education", "Skills", "Certifications", "Projects"
|
|
256
|
+
- No text in images/SVGs
|
|
257
|
+
- No critical info in headers/footers
|
|
258
|
+
- UTF-8, selectable text
|
|
259
|
+
- Keywords distributed: Summary (top 5), first bullet of each role, Skills section
|
|
260
|
+
|
|
261
|
+
**Design:**
|
|
262
|
+
- Fonts: Space Grotesk (headings, 600-700) + DM Sans (body, 400-500)
|
|
263
|
+
- Fonts self-hosted: `fonts/`
|
|
264
|
+
- Header: Space Grotesk 24px bold + cyan→purple 2px gradient + contact info
|
|
265
|
+
- Section headers: Space Grotesk 13px uppercase, cyan color `hsl(187,74%,32%)`
|
|
266
|
+
- Body: DM Sans 11px, line-height 1.5
|
|
267
|
+
- Company names: purple `hsl(270,70%,45%)`
|
|
268
|
+
- Margins: 0.6in
|
|
269
|
+
- Background: white
|
|
270
|
+
|
|
271
|
+
**Keyword injection strategy (ethical):**
|
|
272
|
+
- Reformulate real experience using the exact vocabulary from the JD
|
|
273
|
+
- NEVER add skills the candidate doesn't have
|
|
274
|
+
- Example: JD says "RAG pipelines" and CV says "LLM workflows with retrieval" → "RAG pipeline design and LLM orchestration workflows"
|
|
275
|
+
|
|
276
|
+
**Writing style — Anti-AI-detection (CRITICAL):**
|
|
277
|
+
ATS platforms (Indeed, LinkedIn, Workday) flag AI-generated CVs. All generated text MUST read as human-written:
|
|
278
|
+
- **Vary sentence length.** Mix short fragments with longer sentences. Don't make every bullet the same length.
|
|
279
|
+
- **Start bullets differently.** Bullets MUST NOT all begin with a past-tense action verb — mix in noun-led and metric-led openings.
|
|
280
|
+
- **Use the candidate's own phrasing from cv.md when possible.** Reformulate for keywords, but preserve their voice.
|
|
281
|
+
- **NEVER use these AI-hallmark words:** "leveraged", "utilized", "spearheaded", "orchestrated" (as metaphor), "cutting-edge", "passionate about", "drive innovation", "synergy", "holistic approach", "navigate complex", "foster collaboration".
|
|
282
|
+
- **Use plain, specific verbs.** "Built" not "architected". "Ran" not "orchestrated". "Fixed" not "remediated".
|
|
283
|
+
- **Don't over-polish.** Real CVs have minor asymmetries — one job has 4 bullets, another has 3. Don't normalize everything.
|
|
284
|
+
- **Self-check before generating HTML:** (1) Do 3+ bullets start with same word? Fix. (2) Are all bullets same length? Vary. (3) Any AI-hallmark words? Rewrite.
|
|
285
|
+
|
|
286
|
+
**Template placeholders (in cv-template.html):**
|
|
287
|
+
|
|
288
|
+
| Placeholder | Content |
|
|
289
|
+
|-------------|---------|
|
|
290
|
+
| `{{LANG}}` | `en` or `es` |
|
|
291
|
+
| `{{PAGE_WIDTH}}` | `8.5in` (letter) or `210mm` (A4) |
|
|
292
|
+
| `{{NAME}}` | (from profile.yml) |
|
|
293
|
+
| `{{EMAIL}}` | (from profile.yml) |
|
|
294
|
+
| `{{LINKEDIN_URL}}` | (from profile.yml) |
|
|
295
|
+
| `{{LINKEDIN_DISPLAY}}` | (from profile.yml) |
|
|
296
|
+
| `{{PORTFOLIO_URL}}` | (from profile.yml) |
|
|
297
|
+
| `{{PORTFOLIO_DISPLAY}}` | (from profile.yml) |
|
|
298
|
+
| `{{LOCATION}}` | (from profile.yml) |
|
|
299
|
+
| `{{SECTION_SUMMARY}}` | Professional Summary / Resumen Profesional |
|
|
300
|
+
| `{{SUMMARY_TEXT}}` | Personalized summary with keywords |
|
|
301
|
+
| `{{SECTION_COMPETENCIES}}` | Core Competencies / Competencias Core |
|
|
302
|
+
| `{{COMPETENCIES}}` | `<span class="competency-tag">keyword</span>` × 6-8 |
|
|
303
|
+
| `{{SECTION_EXPERIENCE}}` | Work Experience / Experiencia Laboral |
|
|
304
|
+
| `{{EXPERIENCE}}` | HTML for each job with reordered bullets |
|
|
305
|
+
| `{{SECTION_PROJECTS}}` | Projects / Proyectos |
|
|
306
|
+
| `{{PROJECTS}}` | HTML for top 3-4 projects |
|
|
307
|
+
| `{{SECTION_EDUCATION}}` | Education / Formacion |
|
|
308
|
+
| `{{EDUCATION}}` | HTML for education |
|
|
309
|
+
| `{{SECTION_CERTIFICATIONS}}` | Certifications / Certificaciones |
|
|
310
|
+
| `{{CERTIFICATIONS}}` | HTML for certifications |
|
|
311
|
+
| `{{SECTION_SKILLS}}` | Skills / Competencias |
|
|
312
|
+
| `{{SKILLS}}` | HTML for skills |
|
|
313
|
+
|
|
314
|
+
### Step 5 — Tracker Line
|
|
315
|
+
|
|
316
|
+
Write a single TSV line to:
|
|
317
|
+
```
|
|
318
|
+
batch/tracker-additions/{{ID}}.tsv
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
TSV format (single line, no header, 9 tab-separated columns):
|
|
322
|
+
```
|
|
323
|
+
{next_num}\t{{DATE}}\t{company}\t{role}\t{status}\t{score}/5\t{pdf_emoji}\t[{{REPORT_NUM}}](reports/{{REPORT_NUM}}-{company-slug}-{{DATE}}.md)\t{one_line_note}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**TSV columns (exact order):**
|
|
327
|
+
|
|
328
|
+
| # | Field | Type | Example | Validation |
|
|
329
|
+
|---|-------|------|---------|------------|
|
|
330
|
+
| 1 | num | int | `647` | Sequential, max existing + 1 |
|
|
331
|
+
| 2 | date | YYYY-MM-DD | `2026-03-14` | Evaluation date |
|
|
332
|
+
| 3 | company | string | `Datadog` | Short company name |
|
|
333
|
+
| 4 | role | string | `Staff AI Engineer` | Role title |
|
|
334
|
+
| 5 | status | canonical | `Evaluated` | MUST be canonical (see states.yml) |
|
|
335
|
+
| 6 | score | X.XX/5 | `4.55/5` | Or `N/A` if not scorable |
|
|
336
|
+
| 7 | pdf | emoji | `✅` or `❌` | Whether PDF was generated |
|
|
337
|
+
| 8 | report | md link | `[647](reports/647-...)` | Link to report |
|
|
338
|
+
| 9 | notes | string | `APPLY HIGH...` | 1-sentence summary |
|
|
339
|
+
|
|
340
|
+
**IMPORTANT:** The TSV order has status BEFORE score (col 5→status, col 6→score). In the tracker day files the order is reversed (col 5→score, col 6→status). merge-tracker.mjs handles the conversion.
|
|
341
|
+
|
|
342
|
+
**Valid canonical states:** `Evaluated`, `Applied`, `Responded`, `Interview`, `Offer`, `Rejected`, `Discarded`, `SKIP`
|
|
343
|
+
|
|
344
|
+
Where `{next_num}` is calculated by reading all entries across day files in `data/applications/` and taking the max entry number.
|
|
345
|
+
|
|
346
|
+
### Step 6 — Final Output
|
|
347
|
+
|
|
348
|
+
When finished, print a JSON summary to stdout for the orchestrator to parse (template uses `{{ID}}` / `{company}` placeholders — substitute before emitting):
|
|
349
|
+
|
|
350
|
+
```
|
|
351
|
+
{
|
|
352
|
+
"status": "completed",
|
|
353
|
+
"id": "{{ID}}",
|
|
354
|
+
"report_num": "{{REPORT_NUM}}",
|
|
355
|
+
"company": "{company}",
|
|
356
|
+
"role": "{role}",
|
|
357
|
+
"score": {score_num},
|
|
358
|
+
"pdf": "{pdf_path}",
|
|
359
|
+
"report": "{report_path}",
|
|
360
|
+
"error": null
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
If something fails:
|
|
365
|
+
```
|
|
366
|
+
{
|
|
367
|
+
"status": "failed",
|
|
368
|
+
"id": "{{ID}}",
|
|
369
|
+
"report_num": "{{REPORT_NUM}}",
|
|
370
|
+
"company": "{company_or_unknown}",
|
|
371
|
+
"role": "{role_or_unknown}",
|
|
372
|
+
"score": null,
|
|
373
|
+
"pdf": null,
|
|
374
|
+
"report": "{report_path_if_exists}",
|
|
375
|
+
"error": "{error_description}"
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## Global Rules
|
|
382
|
+
|
|
383
|
+
### NEVER
|
|
384
|
+
1. Fabricate experience or metrics
|
|
385
|
+
2. Modify cv.md, i18n.ts, or portfolio files
|
|
386
|
+
3. Share the phone number in generated messages
|
|
387
|
+
4. Recommend comp below market rate
|
|
388
|
+
5. Generate a PDF without reading the JD first
|
|
389
|
+
6. Use corporate-speak
|
|
390
|
+
7. Use AI-hallmark words: "leveraged", "utilized", "spearheaded", "orchestrated" (as metaphor), "cutting-edge", "passionate about", "drive innovation", "synergy", "holistic approach". ATS platforms flag these.
|
|
391
|
+
|
|
392
|
+
### ALWAYS
|
|
393
|
+
1. Read cv.md, llms.txt, and article-digest.md before evaluating
|
|
394
|
+
2. Detect the role's archetype and adapt the framing
|
|
395
|
+
3. Cite exact CV lines when there's a match
|
|
396
|
+
4. Use WebSearch for comp and company data
|
|
397
|
+
5. Generate content in the JD's language (EN default)
|
|
398
|
+
6. Be direct and actionable — no fluff
|
|
399
|
+
7. When generating English text (PDF summaries, bullets, STAR stories), use native tech English: short sentences, action verbs, no unnecessary passive voice, no "in order to" or "utilized"
|