How the Language Gate Filters Job Postings in the AI-Job-Search Repository
The language gate is a deal-breaker rule that filters job postings based on the candidate's declared language capabilities, assigning each posting a PASS, FLAG, or FAIL verdict during the /rank command.
The language gate ensures that job postings match the candidate's actual language skills as defined in the Languages table of CLAUDE.md. This prevents wasted time on positions requiring fluency in languages the candidate does not speak or where their proficiency falls short of requirements. According to the MadsLorentzen/ai-job-search source code, the gate operates as a structured evaluation layer within the broader job scoring framework.
Where the Language Gate Is Defined
The core logic for the language gate resides in .claude/skills/job-application-assistant/04-job-evaluation.md. This file establishes:
- The candidate's Languages table as the authoritative data source
- Comparison rules between required and declared proficiency levels
- The three-verdict classification system (PASS, FLAG, FAIL)
The gate functions as one of several "deal-breaker" evaluations alongside location and other filters, but it applies distinct logic based on partial matches rather than binary inclusion.
How the Language Gate Verdict Works
When the /rank command executes Step 2 (batch-fetch and score), each job posting receives a language_gate field with one of three possible values:
| Verdict | When Applied | Effect on Results |
|---|---|---|
| PASS | No language required, OR required proficiency ≤ candidate's declared level | Job proceeds normally; language_gate omitted or null |
| FLAG | Required language is declared, BUT required proficiency exceeds candidate's level | Job retained with ⚠ marker and language_note displayed |
| FAIL | Required language not declared at all | Job excluded from shortlist, listed under "Excluded" |
The language_note field accompanies FLAG and FAIL verdicts, quoting the specific requirement that triggered the mismatch. This transparency allows candidates to understand why a posting was demoted or removed.
Implementation Flow in the /rank Command
The orchestration logic in .claude/commands/rank.md implements the gate through four discrete steps:
- Load State – Import the scoring framework from
04-job-evaluation.mdand candidate profile data - Batch-Fetch and Score – For each posting, the scoring agent identifies language requirements and compares against declared capabilities, emitting JSON with
language_gateandlanguage_note - Aggregate and Rank – Apply veto logic: FAIL entries removed, FLAG entries highlighted, PASS entries unchanged
- Persist – Write
language_gateandlanguage_noteback tojob_scraper/seen_jobs.jsonfor reproducibility in re-rankings
This persistence layer ensures that --all re-ranking commands can reproduce identical decisions without re-invoking the scoring agent.
Code Examples
Scoring Agent Output
The scoring agent produces structured JSON for each evaluated posting:
{
"key": "12345",
"status": "scored",
"scores": { "technical": 78, "experience": 65, "behavioral": 55, "career": 72 },
"location": "PASS",
"language_gate": "FLAG",
"language_note": "Requires German fluency (candidate level: B1)",
"deadline": null,
"strengths": ["Strong Python experience", "Relevant fintech background"],
"gaps": ["German fluency needed"],
"language": "en"
}
Veto Application Logic
The ranking step implements gate enforcement through conditional branching:
def apply_language_gate(job):
gate = job["language_gate"]
note = job.get("language_note")
if gate == "FAIL":
# Exclude from shortlist, add to excluded list
excluded.append((job, f"language FAIL: {note}"))
return None
if gate == "FLAG":
# Keep, but mark with warning
job["flags"].append("⚠ language")
job["notes"].append(note)
# PASS – nothing to modify
return job
Shortlist Display Format
Flagged postings appear with visual indicators in the ranked output:
- Senior Backend Engineer at FinTech SA – 78 – Strong Fit – ⚠ – language NOTE: Requires German fluency (candidate level: B1)
Test Coverage
The regression test suite in tests/test_rank_command.py validates gate behavior through four specific assertions:
- Schema includes
language_gateandlanguage_notefields - Verdict set matches location veto set (PASS/FAIL/FLAG)
- FAIL verdicts trigger proper exclusion documentation
- Persistence into
seen_jobs.jsonfunctions correctly
These guards prevent regression as the evaluation framework evolves.
Key Implementation Files
| File | Purpose |
|---|---|
.claude/skills/job-application-assistant/04-job-evaluation.md |
Gate definition and Languages table reference |
.claude/commands/rank.md |
/rank command orchestration and veto logic |
tests/test_rank_command.py |
Regression tests for gate behavior |
job_scraper/seen_jobs.json |
Runtime storage of gate results |
Summary
- The language gate evaluates job postings against candidate-declared language capabilities during the
/rankcommand - Three verdicts exist: PASS (proceed), FLAG (warn but include), and FAIL (exclude entirely)
- Gate logic is defined in
04-job-evaluation.mdand orchestrated throughrank.md - Results persist in
seen_jobs.jsonto enable reproducible re-rankings - Test coverage in
test_rank_command.pyensures behavioral stability
Frequently Asked Questions
What happens if a job posting doesn't specify any language requirement?
The language gate assigns PASS automatically. Since no constraint exists to violate, the posting proceeds through ranking without any language-related annotation or flag.
Can I override a FAIL verdict and still view the excluded posting?
The source implementation does not provide an override mechanism within the standard /rank workflow. Excluded postings appear only in the "Excluded" section with explanatory language_note text. Modifying this would require changes to the veto logic in rank.md.
How does the gate handle proficiency levels like "fluent" versus "conversational"?
The comparison logic in 04-job-evaluation.md maps declared proficiency levels against requirements. When the candidate's level meets or exceeds the requirement, PASS results. When the candidate has the language but at insufficient proficiency, FLAG applies. The specific mapping of named levels (B1, fluent, conversational) depends on the standardized schema in the Languages table.
Why are FLAG and FAIL treated differently?
FLAG indicates a surmountable gap—the candidate possesses foundational capability in the required language and could potentially improve. FAIL indicates complete absence of the language from the candidate's profile, making the mismatch fundamental rather than incremental. This distinction allows candidates to prioritize applications where language acquisition might close the gap.
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 →