Commit Graph
30 Commits
Author SHA1 Message Date
Mads LorentzenandClaude Fable 5.1 0bcfd75e60 fix(guards): read .gitignore like git, allowlist settings.json keys, refuse workspaces and bunfig.toml
Three findings on tools/security_guards.py and tools/install_portal_clis.py.

GHSA-rv99-7xf2-8f4p (Martin Vlach, @Huge): the gitignore guard stripped
both ends of each line, but git drops only unescaped trailing whitespace,
so " salary_data.json" satisfied the required-rule check while git had
stopped ignoring the file. Only the root file was read, though a
.gitignore in a subdirectory outranks it, so a negation there re-included
personal data with CI green. Lines are now read as git reads them, and
every .gitignore below the root (outside .git and node_modules) is checked
for negations; an intentional one is allowlisted as "<dir>/.gitignore:!p".

GHSA-cqcv-crx7-x7q7 (@folovco, @Huge): the guard checked allow, ask, deny
and hooks and ignored every other key, so env, apiKeyHelper, a statusLine
command, enableAllProjectMcpServers, permissions.defaultMode or
additionalDirectories passed CI. Any top-level key outside
ALLOWED_SETTINGS_KEYS and any permissions key outside
ALLOWED_PERMISSIONS_KEYS now fails.

GHSA-wq7j-x5jq-pjrw (@folovco, @Huge), on top of #718's --ignore-scripts
(cherry-picked, rudycelekli): the installer and check 3 now refuse a
manifest that declares workspaces (whose packages bring their own
lifecycle scripts; a workspace postinstall ran under Bun 1.3.10) or that
has a bunfig.toml beside it (which reconfigures the install). The
advisory's workspace proof of concept is now skipped before bun runs.

Twelve new tests, all failing before this change; SECURITY.md, README and
SETUP describe the new checks.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-27 16:14:35 +01:00
MaverickHQandClaude Opus 5.5 bc2c583c44 fix(tools): confine verify_pdf --dump-text and drop the bare pdftotext allowance
settings.json pre-approves verify_pdf.py with any arguments, and
--dump-text wrote the PDF's text layer to any path it was given,
creating missing parent directories and overwriting existing files.
Reproduced on master through the real CLI: a one-page PDF's text was
written to a new directory outside the repo with no prompt. The CLI now
writes only a .txt under the repo's cv/ or cover_letters/ (where
apply.md Step 5d puts it) and refuses a symlinked target.

Bash(pdftotext:*) is dropped for the same reason: Poppler writes to any
output path, and `pdftotext <file> -` prints any PDF on disk into the
session. verify_pdf.py already wraps it; the documented manual fallback
still works and now asks first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 16:07:33 +01:00
Mads LorentzenandClaude Fable 5.1 7f9edf54c1 chore: point every in-tree reference at ai-job-search-dev/ai-job-search (#776)
The repository is moving from the MadsLorentzen personal account to the
ai-job-search-dev organization. GitHub redirects the old slug, but the
upstream-watch guard compares github.repository against the literal slug
and would start running the fork-only triage job on upstream itself, and
the upstream-check tool and its tests pin the slug too. README, CONTRIBUTING,
SECURITY, SETUP, the CI workflow, the issue-template config and the
CHANGELOG links follow.

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-26 14:19:53 +01:00
Mads LorentzenandClaude Fable 5.1 01a3c0e5f6 security: narrow skill grants, ship ask/deny rules, guard skill frontmatter, GET-only 403 retry (#642)
* security(skills): drop bare Bash and the portal CLI glob from skill grants

A skill's allowed-tools pre-approves the listed tools for the turn that
invokes it, even in an untrusted folder. job-application-assistant granted
bare Bash, Edit and Write; job-scraper granted bun run on any
.agents/skills/*/cli/src/cli.ts. Every Bash command the skills document is
already allowlisted per command in .claude/settings.json, so the bare and
glob grants bought nothing but exposure. The per-portal grants stay in
settings.json, which is where a portal added by /add-portal registers too
(Step 5 now says so).

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

* security(settings): deny exfil-shaped shell and credential reads, always ask on permission-defining files

Deny rules block in every permission mode including bypassPermissions and
override any allow rule or skill grant; ask rules force a prompt even when
a skill's allowed-tools would pre-approve the call. settings.json now
ships both: deny for shell that uploads or opens a remote shell (curl
data/form/upload flags, wget post, scp, sftp, ssh, nc) and for reads of
.env and ~/.ssh, ~/.aws, ~/.gnupg; ask for the files whose content is the
permission surface (settings, skill frontmatter, agents, CI, this guard)
and for git push. security_guards.py requires each rule to stay present,
the same way it requires the personal-data gitignore rules. Prefix rules
are tripwires, not walls; SECURITY.md will say so.

Also allowlists tools/robots_check.py and the upcoming tools/fetch_page.py
so the 403 retry no longer needs a curl grant.

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

* security(guards): hold skill and command allowed-tools to a reviewed allowlist

The guard allowlisted settings.json permissions but never read skill
frontmatter, so the narrow settings allowlist sat next to a bare Bash
grant it could not see. Check 4 parses every .claude/skills/*/SKILL.md,
.agents/skills/*/SKILL.md and .claude/commands/*.md frontmatter with a
stdlib parser (scalar, folded, and list forms) and holds each
allowed-tools entry to ALLOWED_SKILL_TOOLS; a portal skill may
additionally grant exactly its own cli/src/cli.ts, matched by path so no
portal name is hardcoded. Bare Bash and mid-pattern wildcards get their
own message. On master's frontmatter this check reports two failures.

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

* feat(tools): add GET-only fetch_page.py for the browser-header retry

09-web-research.md documented the 403 retry as a curl command with browser
headers plus an inline python3 -c tag-stripper, which meant the workflow
wanted a Bash(curl:*) grant - and curl with a free tail is an upload
channel. fetch_page.py is the same retry as one command with a fixed GET
argv (URL after --, bounded to 45 s / 5 redirects / 10 MB), http(s) only,
robots_check.gate() enforced with no bypass flag, --out refused inside
the repo, and --text for the stripped page. urllib fallback when curl is
absent. The settings.json grant names the script.

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

* docs(security): describe the permission surface as a table; route the 403 retry through fetch_page.py

SECURITY.md now lists every shipped grant with its location, lifetime
and guard, and says plainly what the permission layer does not do: no
sandbox on native Windows, prefix rules are tripwires, WebFetch is
unrestricted by domain, subagents run with the parent's tools (next
change), and Edit/Write stay granted because tailoring a CV is editing
files. 09-web-research.md's retry section is the one fetch_page.py
command (framework_version 1.1.3 -> 1.1.4); apply, rank and scrape point
at it instead of curl. SETUP.md and the README tools tree follow.
CHANGELOG gains a Security section under [Unreleased].

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

* security(review): ask on command frontmatter, portal skills grant only their CLI, bound the urllib fallback

Findings from a fresh-context review of the branch:

- A command's frontmatter is a grant too (check 4 already parses it), so
  Edit(.claude/commands/*.md) joins the required ask rules; without it a
  steered session could write `allowed-tools: Bash` into apply.md with no
  prompt and the next /apply would be pre-approved for bare Bash.
- SECURITY.md promised a portal skill may grant "its own CLI and nothing
  else"; the guard now enforces exactly that instead of own-CLI plus the
  core allowlist. All six shipped portal skills already comply.
- fetch_page.py's urllib fallback now matches curl's 5-redirect cap and
  applies the 10 MB cap after decompression, so the docstring's bounds
  hold on both paths.
- Frontmatter parser: a BOM no longer reads as "missing frontmatter",
  YAML flow lists split correctly, and a non-UTF-8 file fails with a
  message instead of a traceback. Module docstring lists check 4.
- CHANGELOG no longer claims "no new prompt": compile and aux cleanup,
  which the removed bare Bash covered in a skill-invoking turn, now
  prompt, deliberately. "Once per session" wording corrected to per call.
- Three upload-shaped deny siblings added (curl -XPOST, curl --request
  POST, wget --method=POST); /add-portal recon points at fetch_page.py.

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

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-19 17:15:25 +02:00
Mariano Gobea Alcoba 36771d03a8 docs(setup): persist the TinyTeX PATH in the shell profile on macOS (#609)
The TinyTeX snippet exports PATH for the current session only. A new terminal
window then fails with 'command not found: lualatex' although the install worked.
Add the persisted form and a one-line check.
2026-10-17 19:47:35 +02:00
落尘 8a3094f138 feat(tools): install every discovered portal CLI with one command (#540) (#541)
README and SETUP.md hardcoded the six shipped portals in four PowerShell/Bash
loops, so a portal added by /add-portal or borrowed from another fork was
skipped on a fresh clone. tools/install_portal_clis.py uses CI's discover-clis
glob, isolates per-CLI failures, and skips manifests with lifecycle scripts or
trustedDependencies.
2026-10-15 11:32:17 +02:00
Ayobami Adegoke 730dcfb079 fix(setup): stop fork clones from filing issues on the upstream repo by default (#389) (#392)
gh repo fork --clone - SETUP.md's own fork command - sets the upstream
repo as gh's default repository, which gh uses for creating issues and
PRs. A user's own automation running gh issue create from a fork clone
therefore published personal job-search data on the upstream public
tracker. SETUP.md section 2 now includes gh repo set-default in the fork
commands with a point-of-decision warning, and .github/ISSUE_TEMPLATE/
carries the same heads-up the PR template already had for the web path.
Blank issues stay enabled.
2026-08-29 11:10:57 +02:00
sdrarunvarshan dea8140db2 feat(ats): extract PDF text with pypdf before Poppler (#369)
* feat(ats): extract PDF text with pypdf before Poppler

Lead the ATS text-layer check with pypdf (BSD, optional pip install). Fall back to pdftotext -layout -enc UTF-8. No cache directory, no installer, no AGPL pymupdf. Windows users without Poppler still get a mechanical parseability check; visual review remains the last resort.

* Update verify_pdf.py

* Update apply.md

* Update verify_pdf.py

* Update verify_pdf.py
2026-08-26 20:07:03 +02:00
Mads LorentzenandClaude Opus 5 34b8b3f91f fix(onboarding): warn about public forks at the point of decision (#345) (#348)
The quick start walked a new user into gh repo fork - forks of public
repos are always public - and two steps later had /setup write personal
data into tracked files, with the only complete warning in SETUP.md
section 8, a section about pulling updates that a first-time user has no
reason to open during onboarding. A real user hit exactly this (#345).

The warning now sits adjacent to both fork commands (README step 1,
SETUP.md section 2, both pointing at section 8's private-remote recipe),
and /setup checks the origin's visibility BEFORE writing anything: a
public-fork origin gets a confirm-first warning instead of a note after
every file is on disk. A private origin, no origin, or a non-git
directory continues silently. Reported by @basilevs with a complete
reproduction and fix analysis; this implements his fixes (1) and (4).

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 21:33:32 +02:00
670d30ae7e feat(upstream): add commit-level triage and weekly watch for forks (#305) (#320)
Forks tracking this template face a weekly "which of these commits do I
actually care about?" question. check_upstream_updates.py answers it at the
file level (version stamps); this adds the commit-level half.

tools/upstream_triage.py walks the commits a fork is behind and splits them
into "worth reviewing" and "probably skip". Work already ported drops off on
its own via git patch-id, commits touching only files the fork removed are set
aside, and SHAs in .github/upstream-wontport.txt stay hidden. It reports and
nothing more - ready-to-run cherry-pick lines, but no merge, push, or PR,
since on a fork "applies cleanly" is not "correct".

.github/workflows/upstream-watch.yml runs it weekly into one rolling issue. It
no-ops on the upstream template (guarded, and pinned by a test) and uses only
the built-in GITHUB_TOKEN, so it can never write outside its own fork. The two
tools point at each other in their output; README, SETUP 8, and CHANGELOG
introduce them together. Tests cover patch-id matching, relevance filtering,
the won't-port list, and the workflow guard - all offline.

Co-authored-by: Angelina Lok <angelina@chattermill.io>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-11 19:11:24 +02:00
Oscar Madera 20d863044b docs(setup): show git remote add upstream in section 8 (#274)
Section 8 told users to 'git fetch upstream' but never showed how to add that remote, so forks that cloned from their own fork could not follow the steps. Spell out the one-time remote-add command (already printed by tools/check_upstream_updates.py) at the source.
2026-08-02 21:16:07 +02:00
Mads LorentzenandClaude Fable 5 d4b406efff docs(privacy): stop calling a fork 'private working space'; warn at /setup time
Forks of public GitHub repositories are always public, so SETUP.md
section 8's 'your fork is private working space, so commit them' invited
exactly the personal-data exposure it seemed to rule out - the observed
failure mode behind several real forks that pushed filled-in profiles to
public master. Section 8 now states the fork-is-public fact plainly and
documents the safe alternative (private repo + template as upstream
remote), and /setup's completion summary carries a matching privacy note
at the exact moment profile data first lands in tracked files.

Also backfills the CHANGELOG entry for #265.

Prompted by rasstamann's discussion #266.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-01 22:03:22 +02:00
Mads LorentzenandClaude Opus 4.8 905f6e0946 docs(releases): add CHANGELOG + release-based update guidance; sharpen real-path bar (#225)
Addresses #213 (how to keep up with a fast-moving upstream) and closes the
verification loophole surfaced in the 2026-07-22 triage audit.

- Add CHANGELOG.md (Keep a Changelog + semver), with v1.0.0 as the first
  tagged baseline and an Unreleased section for going forward.
- SETUP.md section 8: recommend updating to a tagged release (a vetted,
  described checkpoint) over pulling raw master; fetch --tags and merge a tag.
- README: add a "Staying up to date" pointer to Releases, the CHANGELOG, and
  check_upstream_updates.py.
- CONTRIBUTING.md: sharpen "Claims get verified" - a test that distinguishes
  master from the fix is necessary but not sufficient; the failing input must
  be one the workflow actually produces, not one the test hand-builds. Fixes
  demonstrated only through a synthetic input the real code path never receives
  get declined even when their test is green.

Note: the git tag / GitHub Release for v1.0.0 is intentionally left for the
maintainer to cut.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 11:36:47 +02:00
Oscar Madera 669f5ac1ab docs(setup): add Basic MiKTeX setup instructions for Windows (#186)
Documents the Windows Basic MiKTeX path missing from SETUP.md's minimal-TeX section: enabling silent [MPM]AutoInstall so missing-package installs don't block on a GUI prompt in non-interactive terminals, an mpm pre-install alternative matching the macOS TinyTeX package list, and a PowerShell translation of the existing bash smoke tests. Nested under the LaTeX section as a peer of the TinyTeX/BasicTeX subsection.

By @oscarbol09 (first contribution). Package names, AutoInstall config, and the PowerShell smoke block empirically verified on Windows 11 + MiKTeX.
2026-07-20 18:40:50 +02:00
Mads Lorentzen d2e14418ca docs(setup): document upstream-pull workflow and failure-isolate install loops (#176)
Adds SETUP.md section 8 (pulling upstream updates into a personalized fork: commit-first, check_upstream_updates.py preview, conflicts-as-signal) closing #174, reported by @sharique. Also brings SETUP.md's duplicate install loops up to #157's failure-isolated pattern.
2026-07-17 22:05:43 +02:00
Jaewon Chung ac6a734e16 fix(apply): name CVs main_<company>_<role> to avoid overwrites (#171)
CVs from /apply were named cv/main_<company>.tex, so a second role at the same company overwrote the first (cover letters already carried the role). Aligns CV naming to main_<company>_<role>.tex across apply, add-template, the CV template guide, CLAUDE.md, and SETUP.md; /outcome and /interview fallbacks glob main_<company>*.tex to match both legacy and new names. framework_version bumped on both touched framework files.
2026-07-17 21:26:04 +02:00
Yiğit Ö. Ünver fca1c4234e docs(setup): add needspace to the minimal TeX install list (#147) 2026-07-13 20:45:36 +02:00
fooSynapticandfooSynaptic 6a1240648f docs: document freehire-search in README and SETUP (#103)
The freehire-search CLI is typechecked in CI but was missing from install
instructions, the file tree, and the country-agnostic portal overview.

Co-authored-by: fooSynaptic <19420328+fooSynaptic@users.noreply.github.com>
2026-07-09 21:13:31 +02:00
Sheroy Cooper 22a4438dab docs: prefer python3 in setup examples (#86) 2026-07-09 06:05:16 +02:00
luminmarketinggroup-sys 4807cc846b docs: add minimal TeX setup instructions (#60)
Document a user-level TinyTeX path for minimal LaTeX installs, list the template packages needed by the stock CV and cover-letter templates, and add local smoke-test commands for lualatex/xelatex.
2026-07-08 17:10:32 +02:00
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
mchorari b05fa05b4a Added Windows-friendly PowerShell commands for installing Bun and installing the job-search CLI dependencies. (#41)
Clarified Python and LaTeX prerequisites for Windows users.
Updated the document compilation steps so they work in both Bash and PowerShell
2026-07-07 06:27:51 +02:00
Ayobami Adegoke 79b153764d feat: add /add-portal command for generating local job-portal search skills (#37)
The README has always invited users outside Denmark to build equivalents of
the four Danish portal CLI skills, but doing so meant reverse-engineering
.agents/skills/*/cli/ by hand. /add-portal turns that invitation into a
guided workflow:

- Interviews the user for the portal URL, skill name, market/language
  (trigger phrases in the local language, like the Danish skills), and a
  realistic test query
- Investigates the portal before writing code: search-URL pattern, result
  structure (JSON API preferred over HTML), detail-page pattern, robots.txt
  and access rules. Auth-walled portals are declined; portals with
  restrictive terms get a prominent personal-use-only warning in the
  generated SKILL.md (same as linkedin-search)
- Scaffolds from the canonical structure with linkedin-search as the
  zero-dependency reference, enforcing the shared portal-skill contract:
  search/detail commands, common flags, {meta, results} JSON shape, stderr
  JSON errors, backoff on 429/5xx, chunked parsing
- Mandatory live test-run (search + detail + test suite) before registering
- Optionally wires the portal into /scrape via search-queries.md

The generator is country-agnostic; its output is market-specific and stays
in the user's fork, matching the repo policy that upstream remains a
universal template.

Docs: README (commands list, file structure, Job search tools section) and
SETUP.md (CLI install section pointer).
2026-07-06 21:04:44 +02:00
Terminal Chai 5cc9b779c0 docs: align setup onboarding paths (#36) 2026-07-06 21:03:54 +02:00
Ayobami Adegoke 6b144dc456 feat: add /add-template command for registering custom LaTeX templates (#30)
Users could already swap the stock moderncv/cover.cls templates, but only by
hand-editing the guidance in 05-cv-templates.md and 06-cover-letter-templates.md.
/add-template automates that:

- Interviews the user for the template's instructions: compile engine, fonts
  (bundled files or system), style rules to preserve, and hard page limit
- Stores the template profile-agnostic ([PLACEHOLDER] tokens) under templates/
  with a TEMPLATE.md manifest, so templates are safe to commit and share
- Runs a mandatory test compile with dummy data before registering anything
- Activates via a single managed block in 05/06, which /apply already reads,
  so no changes to the /apply workflow are needed; --use default is a clean
  revert to the stock templates
- --list and --use <name> manage multiple registered templates

Docs: README (commands list, file structure, LaTeX templates section) and
SETUP.md (compile section pointer).
2026-07-05 20:27:33 +02:00
Mads LorentzenandClaude Fable 5 f9c1978c65 docs: add linkedin-search to install lists in README and SETUP (#28)
Follow-up to #20: the linkedin-search CLI landed without being added to
the bun install instructions. Included in both lists with a note that
the install is optional (zero runtime dependencies, dev types only).
Also updated the README file tree and Bun prerequisite wording to
reflect that the toolset is no longer Denmark-only.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 10:59:08 +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
Mads LorentzenandClaude Opus 4.7 83ca0a8557 docs(setup): fix stale pdflatex references to lualatex
Two stragglers in SETUP.md still recommended pdflatex even though the
README, CLAUDE.md, and 05-cv-templates.md all correctly say lualatex.
The compile snippet in section 7 used pdflatex, and the troubleshooting
section described the CV compile as "standard LaTeX." Both updated to
match the rest of the documentation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 21:03:20 +02:00
Mads LorentzenandClaude Opus 4.7 00678f9669 docs: document PDF verification loop and relevance-weighted cutting
Updates README.md and SETUP.md to reflect the new /apply workflow
additions shipped in the previous commit:

- Bumps the /apply step list from 6 to 7, adding "Compile and inspect"
  between Revise and Present
- Adds a "What makes this workflow different" subsection highlighting the
  PDF verification loop, relevance-weighted CV cutting, drafter-reviewer
  separation, and token-efficient dispatching
- Updates prerequisites note to call out lualatex (CV) and xelatex (cover
  letter) explicitly, with the reason each engine is required
- Updates SETUP.md's LaTeX section to match (pdflatex -> lualatex for the
  CV, with the MiKTeX fontawesome5 caveat)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 19:36:45 +02:00
AI Job SearchandClaude Opus 4.6 c66d599d75 Initial release: AI-powered job application framework
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 08:34:06 +01:00