How Cover Letter Sentences Are Cut Based on Relevance in AI Job Search

The /apply workflow in the MadsLorentzen/ai-job-search repository uses a three-pass relevance-weighted algorithm that removes sentences re-stating CV bullets first, then content without job-posting keyword matches, and finally the weakest keyword-matched material until the document fits one page.

The MadsLorentzen/ai-job-search repository automates job applications by ensuring cover letters never exceed a single page through intelligent content trimming. When generated text overflows, the system applies a relevance-weighted cutting algorithm that evaluates every sentence against the job posting and existing CV content. This approach prioritizes the preservation of job-specific keywords and unique achievements over redundant or generic statements.

The Three-Pass Removal Hierarchy

The algorithm operates through three ordered passes, each targeting progressively more relevant content only when necessary. According to .claude/commands/apply.md at line 251, the system follows this strict removal sequence:

  • Pass 1: Duplicate CV content — Sentences that merely re-state bullets already present in the CV receive a relevance score of 0 and are removed first.
  • Pass 2: Non-keyword matches — Whole bullets or sentences containing no posting keywords are eliminated next, as they lack job-specific relevance.
  • Pass 3: Keyword-matched content — Only after exhausting all lower-tier material does the system remove bullets that actually contain posting keywords, preserving the strongest matches until the last possible moment.

This hierarchy prevents the naive "cut from the bottom" approach and ensures the most job-relevant material survives the trimming process.

How Relevance Scoring Works

Each line or bullet receives an aggregate score based on three factors defined in .claude/skills/job-application-assistant/05-cv-templates.md (lines 342-345):

  1. Keyword relevance — The density of matching terms from the target job posting.
  2. Uniqueness — Whether the same idea appears elsewhere in the document (duplicates are penalized).
  3. Dependency — Whether the sentence merely repeats CV content or provides necessary cover-letter context.

The line with the smallest aggregate score is always cut first.

Python Implementation

The following implementation mirrors the workflow described in the repository documentation. The relevance_score function calculates value based on posting keywords and CV duplication, while trim_cover_letter iteratively removes the lowest-scoring lines:

def relevance_score(line, posting_keywords, cv_bullets):
    # 1️⃣ Keyword relevance – number of posting keywords found

    keyword_hits = sum(kw in line.lower() for kw in posting_keywords)

    # 2️⃣ Uniqueness – penalize if the same idea appears elsewhere

    duplicate = any(line.strip() == other.strip() for other in cv_bullets)

    # 3️⃣ Dependency – line that merely repeats a CV bullet gets 0 relevance

    repeats_bullet = any(bullet in line for bullet in cv_bullets)

    # Higher score = more valuable; lower = candidate for removal

    return keyword_hits - (duplicate or 0) - (repeats_bullet or 0)


def trim_cover_letter(lines, posting_keywords, cv_bullets, max_chars):
    """Iteratively drop the lowest‑scoring line until length constraint is met."""
    while sum(len(l) for l in lines) > max_chars:
        # Compute scores for all remaining lines

        scores = [relevance_score(l, posting_keywords, cv_bullets) for l in lines]

        # Identify the line with the smallest score (lowest relevance)

        idx_to_remove = scores.index(min(scores))

        # Remove it – respects the three‑pass order implicitly:

        #   0‑score → repeats bullet, then non‑keyword, then keyword‑only lines.

        del lines[idx_to_remove]

    return lines

The apply command integrates this logic by extracting posting keywords and CV bullets, then processing the raw LaTeX cover letter body through trim_cover_letter before compilation.

Summary

  • The /apply workflow triggers automatic trimming when cover letters exceed one page.
  • Three ordered passes remove content: CV duplicates first, then non-keyword material, then keyword-matched sentences.
  • A composite relevance score balances keyword density, uniqueness, and CV dependency.
  • The algorithm preserves the most job-relevant content by cutting the lowest aggregate scores first.
  • Implementation details reside in .claude/commands/apply.md and related skill files.

Frequently Asked Questions

What triggers the cover letter trimming process?

The trimming process activates automatically during the /apply workflow when the generated LaTeX content exceeds the maximum character limit for a single page. The system calculates the total character count and invokes trim_cover_letter until the document fits within the constraint.

Why are CV duplicates removed before non-keyword content?

Sentences that re-state CV bullets receive a relevance score of 0 because they add no new information to the application. According to the implementation in .claude/commands/apply.md, removing redundant content first preserves space for unique achievements and job-specific qualifications that actually differentiate the candidate.

How does the algorithm handle sentences with multiple posting keywords?

Sentences containing posting keywords receive higher aggregate scores based on keyword density, making them unlikely candidates for removal until Pass 3. Even then, the algorithm removes only the lowest-scoring keyword-matched lines first, ensuring the strongest thematic matches survive the cutting process.

Is this trimming logic shared between CVs and cover letters?

Yes, the repository uses the same relevance-weighted cutting principles for both documents. The README.md at line 256 introduces this unified approach, though the specific implementation details for cover letters are documented separately in the apply command and CV template skill files.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →