# How to Generate Cover Letters with Keyword Mirroring and Four-Angle Prompts in Career-Ops

> Generate ATS-friendly cover letters with Career-Ops using keyword mirroring and four-angle prompts. Get your tailored PDF today.

- Repository: [Santiago Fernández de Valderrama/career-ops](https://github.com/santifer/career-ops)
- Tags: how-to-guide
- Published: 2026-08-19

---

**Career-Ops generates tailored cover letters by mirroring job-description keywords and requiring four strategic angle prompts before drafting, producing ATS-compatible PDFs via `generate-cover-letter.mjs`.**

The open-source Career-Ops toolkit automates candidate-facing documents through structured Markdown workflows. When you generate cover letters with **keyword mirroring** and **four-angle prompts**, the system enforces a rigorous interaction model defined in [`modes/cover.md`](https://github.com/santifer/career-ops/blob/main/modes/cover.md) before emitting a single line of prose.

## Input Files and Prerequisites

Before invoking the cover-letter mode, populate three core data files. **[[`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml)](https://github.com/santifer/career-ops/blob/main/config/profile.yml)** stores contact fields such as `candidate.name`, `email`, and notice-period defaults. **[[`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md)](https://github.com/santifer/career-ops/blob/main/cv.md)** supplies the achievement bullets and professional summary used for scoring and evidence. Optional richer proof points live in **[[`article-digest.md`](https://github.com/santifer/career-ops/blob/main/article-digest.md)](https://github.com/santifer/career-ops/blob/main/article-digest.md)**, which overrides CV data when topics overlap.

## Launch the Cover-Letter Mode

Start the workflow from your terminal using the Career-Ops CLI. You can pass an existing report slug or paste a job description interactively.

```bash

# Invoke with an existing report slug

career-ops cover {slug}

# Or launch interactively and paste the JD

career-ops cover

```

## Job Description Validation and Parsing

The mode first checks that a complete **job description** is present, including role title, company, and responsibilities. It then extracts location, top competencies, domain, start-date cues, language requirements, and tone. Concurrently, the system runs three web-search queries covering product strategy, challenges, and news, synthesizing the results into a two-to-three-sentence briefing.

## Keyword Extraction and Mirroring

Career-Ops extracts the top 8–10 exact phrases from the JD and classifies them into **ATS-critical** and **human-trust** groups. This **keyword mirroring** step is shown to you for confirmation before drafting begins. Any JD keywords that cannot be incorporated are reported in the post-generation notes.

## The Four-Angle Prompt System

Before any text is drafted, [`modes/cover.md`](https://github.com/santifer/career-ops/blob/main/modes/cover.md) enforces four mandatory answers. The system will not proceed until all four are received:

- **A. Why this role or company?** — Capture a strategic or personal motivation.
- **B. What problem will you solve?** — Ground this in the company research briefing.
- **C. How will you approach it?** — Outline a credible first-day or first-month plan.
- **D. Which tone?** — Choose formal, direct, conversational, or JD-mirrored voice.

## Gap Detection and Achievement Selection

The workflow detects mismatches across domain, notice period, language, and title, prompting you to acknowledge or explain each gap. Simultaneously, it scores every bullet in [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) against the JD’s required competencies and selects the 4–5 highest-scoring achievements, preserving exact wording and metrics. A fact-validation step then verifies that all metric claims and employer or tool mentions are backed by [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) or [`article-digest.md`](https://github.com/santifer/career-ops/blob/main/article-digest.md).

## Drafting, Template Resolution, and PDF Generation

The draft follows a fixed structure: header, salutation, opening, profile intro, achievements, problem section, closing, and optional language closing. The chat-based draft is presented for your approval before any PDF generation begins. After you approve, the system resolves the HTML template via the shared resolver, which loads **[[`templates/cover-letter-template.html`](https://github.com/santifer/career-ops/blob/main/templates/cover-letter-template.html)](https://github.com/santifer/career-ops/blob/main/templates/cover-letter-template.html)** for PDF rendering:

```bash
node cv-templates.mjs resolve cover ...

```

Next, Career-Ops assembles a JSON payload and calls **[`generate-cover-letter.mjs`](https://github.com/santifer/career-ops/blob/main/generate-cover-letter.mjs)** to render an A4 PDF. The payload includes candidate metadata, role details, greeting, opening paragraph, curated achievements, and the problem statement.

```json
{
  "candidate": {
    "name": "Alice Example",
    "email": "alice@example.com",
    "phone": "555-123-4567",
    "location": "San Francisco, CA",
    "linkedin": "alice-linkedin",
    "github": "alice-github",
    "credentials": ["MSc Computer Science", "AWS Certified Solutions Architect"]
  },
  "letter": {
    "role_title": "Senior Machine Learning Engineer",
    "company": "Acme AI",
    "city": "Seattle",
    "date": "2026-08-19",
    "greeting": "Dear Jane Smith,",
    "opening": "I’m excited to apply because Acme’s push into autonomous-driving aligns with my work on large-scale perception pipelines.",
    "profile_intro": "With 6 years building end-to-end ML systems, I lead cross-functional teams delivering production-grade models.",
    "achievements": [
      {"lead":"Reduced inference latency", "impact":"from 120 ms to 38 ms, saving $250K annually"},
      {"lead":"Scaled data pipelines", "impact":"to process 5 PB/day, enabling new product features"},
      {"lead":"Mentored junior engineers", "impact":"to increase code-review throughput by 30 %"}
    ],
    "problems_section": "I can help Acme tackle sensor-fusion latency by applying my experience with on-device optimisation.",
    "closing": "I’m available to start in 4 weeks and would love to discuss how I can accelerate your roadmap.",
    "language_closing": null
  },
  "output_path": "output/acme-ai-senior-ml-engineer-cover.pdf"
}

```

Generate the final artifact by passing the payload to the script:

```bash
node generate-cover-letter.mjs --payload /tmp/cover-payload-acme-ai.json

```

After generation, Career-Ops reports any JD keywords that could not be incorporated, documents gap-acknowledgment decisions, and confirms word-count compliance.

## Shared Writing Guardrails

All cover-letter outputs inherit rules from **[[`modes/_writing.md`](https://github.com/santifer/career-ops/blob/main/modes/_writing.md)](https://github.com/santifer/career-ops/blob/main/modes/_writing.md)**, which enforces **ATS-compatible** style, active voice, buzzword bans, and length limits. Personalization overrides from **[[`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md)](https://github.com/santifer/career-ops/blob/main/modes/_profile.md)** are applied after the generic rules, ensuring the final voice reflects your archetype and narrative preferences.

## Summary

- The cover-letter workflow is orchestrated by [`modes/cover.md`](https://github.com/santifer/career-ops/blob/main/modes/cover.md) inside the `santifer/career-ops` repository.
- **Keyword mirroring** splits the top 8–10 JD phrases into ATS-critical and human-trust groups for confirmed insertion.
- **Four-angle prompts** (Why, What, How, Tone) are mandatory gatekeepers that block drafting until answered.
- Achievements are scored against the JD and selected from [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md), while facts are validated against [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) and [`article-digest.md`](https://github.com/santifer/career-ops/blob/main/article-digest.md).
- Final PDF generation runs through `generate-cover-letter.mjs` using a JSON payload and an HTML template resolved by `cv-templates.mjs`.

## Frequently Asked Questions

### What files does Career-Ops read before generating a cover letter?

The system reads [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml) for candidate identity fields, [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) for achievement bullets, and optionally [`article-digest.md`](https://github.com/santifer/career-ops/blob/main/article-digest.md) for supplemental proof points. It also consumes the job description you provide interactively or through a slug.

### Can I generate a cover letter without answering the four-angle prompts?

No. As implemented in [`modes/cover.md`](https://github.com/santifer/career-ops/blob/main/modes/cover.md), the workflow explicitly blocks drafting until you supply all four answers: why the role, what problem you will solve, how you will approach it, and which tone to use.

### How does Career-Ops ensure the cover letter is ATS-friendly?

The system extracts 8–10 exact phrases from the JD and categorizes them into ATS-critical keywords. Shared guardrails in [`modes/_writing.md`](https://github.com/santifer/career-ops/blob/main/modes/_writing.md) further enforce ATS-compatible formatting, active voice, and banned buzzwords.

### What happens if my CV does not support a claim in the draft?

A fact-validation step runs before PDF generation to verify that every metric claim and employer or tool mention is backed by data in [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) or [`article-digest.md`](https://github.com/santifer/career-ops/blob/main/article-digest.md). Unverifiable claims are flagged rather than printed.