Commit Graph
2 Commits
Author SHA1 Message Date
Ayobami Adegoke 2551824ecb feat: add ATS & keyword verification pass to /apply's compile-and-inspect loop (#40)
An ATS reads the compiled PDF's embedded text layer, not the rendered page,
and LaTeX can silently produce PDFs whose text extracts as garbage: icon
glyphs where contact details should be, (cid:*) markers from fonts without
Unicode mappings, interleaved lines from multi-column layouts. This matters
more now that /add-template lets users bring arbitrary templates. The
existing Step 5 loop verifies what a human sees; this adds verification of
what a parser sees.

New Step 5d in /apply (CV only - cover letters rarely go through keyword
screening; cleanup renumbered to 5e):

- Extract the CV PDF's text layer with pdftotext -layout. pdftotext
  (poppler) is an optional dependency: if missing, the mechanical check is
  skipped with a warning and keyword coverage falls back to the visual PDF
  read - the same graceful-skip pattern as salary_lookup.py
- Parseability checks verified against a real extraction of the stock
  template: email/phone must survive as literal text (fontawesome icons
  extract as harmless glyph-name noise like MOBILE-ALT/Envelope, but a
  contact detail carried only by an icon or hyperlink is invisible to ATS),
  no (cid:*) or replacement-character garbage, reading order matching
  visual order, dates present
- Keyword coverage reuses the required/preferred list from Step 1, matched
  in the posting's language, reported as covered / synonym-only /
  missing-have-it / missing-gap. Honesty rule enforced: keywords the
  profile genuinely supports get added to experience bullets; genuine gaps
  stay visible, never stuffed

Integration: CLAUDE.md verification checklist section, ATS Parseability
guidance in 05-cv-templates.md, narrow Bash(pdftotext:*) entry in the
pre-approved permissions (keeping with the tightened scope from #27),
cv/*.txt gitignored (extraction is personal data; also deleted by the
step itself), and optional-dependency docs in README and SETUP.
2026-07-07 06:28:59 +02:00
Mads LorentzenandClaude Fable 5 f15b9fb65d Tighten pre-approved permissions and untrack settings.local.json (#27)
* fix: move scoped permissions to settings.json, drop curl, untrack settings.local.json

Addresses #23:
- Remove pre-approved Bash(curl:*) - no agent workflow uses curl, and a
  toolkit that routinely feeds untrusted job postings to the model should
  not ship a pre-approved exfiltration-capable command
- Move shared permissions to .claude/settings.json (committed by
  convention) and scope them tighter: Bash(bun run:*) for the job portal
  CLIs, Bash(python/python3 salary_lookup.py:*) for salary lookups
- Untrack .claude/settings.local.json - it was committed despite being
  listed in .gitignore; the file stays local for personal overrides

Reported-by: @josealfonsomora

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(setup): warn existing cloners about stale settings.local.json

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 10:56:17 +02:00