This release is about the steps after the scan: reading an interview invite, keeping your CV in your own words and checking a UK visa sponsor before you apply. It comes from 99 people over two weeks, 69 of them contributing for the first time.
Highlights
- Interview invites, read for you. Paste an invite and
invite-match.mjslists what it asks of you (no AI, a recording, camera on, ID, a panel) (#5734) and drafts a short clarification email that you send yourself (#6100).panelist-roles.mjsclassifies the people on the panel by role (#5799), and what an interviewer said they care about carries into your plan for the next round (#5801). All by @Schlaflied. - Your CV, in your words. PDF and LaTeX output stop when generated text adds a stock resume phrase or a dash that your own CV does not use. Lines you wrote stay as they are. (#6178 by @mbrow190)
- Less of you in the prompt. With
privacy.redact_contact_info: trueinconfig/profile.yml, the Gemini, OpenAI and OpenRouter evaluator scripts take your name, email, phone and profile links out of the prompt (#2427 by @GambitATJ). Values you list inconfig/privacy.ymlstop a request from the standalone evaluator scripts before it is sent (#5571 by @asimthaha). Both are opt-in, and neither changes what your coding agent sends. - A UK visa sponsor check.
node sponsor-check.mjs --company "<name>"looks the employer up in the Home Office register of licensed sponsors, and--trackerchecks the employers in your tracker. It only reads. (#5790 by @foayenix) - Sixteen more places to look. Apple (#5496 by @kellymmcgrath), ApplicantPro (#6252 by @Schlaflied), Bulldogjob (#6253 by @momoscape), ClearCompany, Homerun and WP Job Manager boards (#5918, #5785, #5878 by @benbalter), Darwinbox (#6416 by @okeken), Deel (#6189 by @dgitman), Factorial (#6394 by @artemtrofymenko), GermanTechJobs (#6346 by @faramirezs), jobs.cz and prace.cz (#5631 by @kosinal), Keka (#6199 by @darkpandawarrior), Notion (#5616 by @IaroslavMazur), Paylocity (#5687 by @ilyakanevskiy) and Zucchetti InRecruiting (#5984 by @Fede046).
If you run scan from a script
- A misspelled top-level key in
portals.ymlnow stopsscan.mjswith exit code 1 and names the file, the key and the likely spelling. Before, the scan found nothing and exited 0. (#6107 by @mbrow190) scan.mjsexits 2 when none of its targets could be read. (#5720 by @vliggio)
Updating
Run node update-system.mjs apply --confirm in your career-ops folder. If you said no to the update prompt earlier, this is the same command.
Thank you
This release carries 450 pull requests from 99 people, 69 of them contributing for the first time.
- @mbrow190: #5706, #5708, #5710, #5769, #5987, #5988, #6034, #6035, #6039, #6040, #6041, #6042, #6043, #6044, #6045, #6046, #6047, #6049, #6050, #6051, #6052, #6053, #6054, #6055, #6056, #6057, #6059, #6060, #6063, #6064, #6065, #6066, #6067, #6068, #6072, #6073, #6074, #6075, #6078, #6080, #6081, #6082, #6083, #6084, #6086, #6087, #6089, #6094, #6096, #6097, #6098, #6099, #6101, #6102, #6103, #6105, #6106, #6107, #6109, #6110, #6114, #6116, #6117, #6118, #6119, #6120, #6121, #6122, #6123, #6124, #6127, #6129, #6130, #6138, #6139, #6142, #6143, #6177, #6178, #6179, #6180, #6181, #6182, #6184, #6240, #6241, #6331, #6332
- @vliggio: #5577, #5581, #5645, #5653, #5655, #5660, #5678, #5694, #5698, #5700, #5707, #5720, #5751, #5762, #5763, #5765, #5766, #5811, #5842, #5844, #5845, #5857, #5922, #5924, #5925, #5926, #5927, #5928, #5944, #5946, #5993, #6031, #6032, #6157, #6160, #6161, #6208, #6215, #6216, #6217, #6218, #6219, #6220, #6221, #6222, #6226, #6227, #6228, #6229, #6231, #6233, #6259, #6271, #6273, #6274, #6277, #6278, #6279, #6280, #6281, #6284, #6285, #6287, #6288, #6291, #6292, #6293, #6296, #6297, #6311, #6312, #6314, #6318, #6319
- @abankar1: #4979, #5827, #5829, #5831, #5832, #5833, #5834, #5835, #5836, #5837, #5838, #5839, #5852, #5855, #5859, #5860, #5861, #5862, #5863, #5864, #5865, #5866, #5867, #5868, #5869, #5870, #5871, #5872, #5873, #5874, #5875, #5876, #5877, #5879, #5880, #5881, #5882, #5883, #5884, #5885, #5886, #5887, #5888, #5889, #5890, #5891, #5892, #5893, #5895, #5898, #5899, #5900, #5902, #5903, #5904, #5907, #5908, #5909, #5910, #5911, #5912, #5913, #6340, #6342, #6343, #6344, #6359, #6361, #6448, #6451, #6492
- @artemtrofymenko: #5787, #5812, #5813, #5919, #5982, #6004, #6005, #6021, #6155, #6303, #6304, #6306, #6307, #6367, #6368, #6393, #6394, #6406, #6445
- @Schlaflied: #5630, #5734, #5738, #5742, #5795, #5798, #5799, #5801, #5998, #6003, #6033, #6095, #6100, #6252, #6348, #6461
- @ncoprod: #5434, #5435, #5443, #5463, #5527, #5716, #5747, #5914, #5915, #5980, #6023, #6025, #6163, #6164
- @rubicon: #5932, #5933, #5936, #5938, #5939, #5942, #5952, #5957, #5958, #6012
- @ilyakanevskiy: #5687, #5753, #5767, #5826, #6006, #6009, #6011, #6465, #6499
- @benbalter (first contribution): #5782, #5784, #5785, #5810, #5878, #5918, #5999, #6000
- @roydonsequeira: #5691, #5703, #6090, #6245, #6302, #6380
- @AdilAzhariOmsan: #6378, #6412, #6431, #6432, #6507
- @bercedev (first contribution): #5806, #5814, #6358, #6414
- @darkpandawarrior: #6199, #6210, #6211, #6212
- @DeryFerd: #5573, #5575, #5896, #5897
- @EngrHarris (first contribution): #6198, #6209, #6301, #6385
- @faramirezs (first contribution): #6345, #6346, #6442, #6443
- @Ali-Pourgheisari (first contribution): #5906, #5917, #6238
- @Codexnever (first contribution): #6310, #6366, #6404
- @elmaroun07-hub: #5817, #6017, #6018
- @okeken (first contribution): #6239, #6416, #6436
- @sogav21 (first contribution): #5990, #6007, #6008
- @Vijaysir0hi (first contribution): #6268, #6269, #6270
- @Zoubeir23: #6257, #6258, #6267
- @AnkitParekh007 (first contribution): #6382, #6383
- @deosiree (first contribution): #6469, #6470
- @Dev-GA-Arjun (first contribution): #5991, #6038
- @dgitman (first contribution): #6189, #6375
- @Ev3nt1ne: #5824, #6196
- @imaimai86 (first contribution): #6150, #6152
- @Kanaparthi89 (first contribution): #6315, #6324
- @kellymmcgrath: #5496, #6154
- @ketpatil77 (first contribution): #5807, #5850
- @luochen211: #5427, #5680
- @momoscape (first contribution): #6253, #6254
- @nessuarez (first contribution): #5754, #5825
- @w21180239 (first contribution): #6438, #6477
- @Abhipatil0065 (first contribution): #5851
- @AdapaRohith (first contribution): #6247
- @alimehdikhan (first contribution): #6328
- @arnavsingh0418 (first contribution): #5996
- @asimthaha (first contribution): #5571
- @atharvasalunke1267 (first contribution): #6405
- @BigBrown10: #5433
- @brunommon: #6070
- @bvs2 (first contribution): #6415
- @Chandru9842 (first contribution): #6027
- @crayaan (first contribution): #5746
- @Dakshx07: #5819
- @drezix (first contribution): #6111
- @evhuynh22 (first contribution): #6185
- @Fede046 (first contribution): #5984
- @foayenix (first contribution): #5790
- @GambitATJ (first contribution): #2427
- @ghouseahmed226-debug (first contribution): #6424
- @Goldloli (first contribution): #6351
- @gregaro: #6341
- @Grove-ovo (first contribution): #6298
- @gyaneshwar18 (first contribution): #6401
- @heydryft (first contribution): #5920
- @Hiba-Malik (first contribution): #6391
- @hippi345 (first contribution): #6286
- @IaroslavMazur: #5616
- @ilya-bogin-keenable (first contribution): #5686
- @imChinmoy (first contribution): #6418
- @imrane92i (first contribution): #5725
- @ixley: #4430
- @jatinukey2 (first contribution): #6435
- @JaxsonD7 (first contribution): #6450
- @JooSeunghyeon (first contribution): #5964
- @kosinal (first contribution): #5631
- @MannXo: #5815
- @Max-To (first contribution): #5788
- @maxmilian: #6336
- @michibastias (first contribution): #5664
- @moldach (first contribution): #5718
- @mrhy7176 (first contribution): #6149
- @MrPhobos (first contribution): #6026
- @nicho810 (first contribution): #6411
- @o66o (first contribution): #6165
- @octo-patch: #5531
- @oegir (first contribution): #6192
- @pei711 (first contribution): #6001
- @pmfgomes (first contribution): #6191
- @pockanoodles (first contribution): #6290
- @prateek942: #6186
- @Ptraaah (first contribution): #6364
- @Raghunath2604 (first contribution): #5404
- @rudy-07 (first contribution): #5822
- @S3yon: #6148
- @shekhar4704 (first contribution): #6453
- @sinia-ai (first contribution): #6478
- @smsajjadzaidi (first contribution): #5712
- @Suraj-12343423 (first contribution): #6242
- @tang-ontheway (first contribution): #6468
- @Tanmay9223: #5792
- @thedisciple (first contribution): #4840
- @unrealinux (first contribution): #5715
- @vikkrantxx7 (first contribution): #5711
- @Yoruxyv: #5690
1.39.0 (2026-11-05)
Features
- add UK Skilled Worker sponsor-licence cross-check (sponsor-check.mjs) (#5790) (97b6b33)
- apple: note postings Apple labels PIPE (#6196) (39287a5)
- ats: classify each ATS rule as structural or content-dependent (#5939) (fe40e51), closes #4798
- ats: give each auditAts check an id and a scope (#5942) (1ac71e4), closes #5940
- batch: add optional single-pass CV-match evaluation mode (--mode match, #5297) (#5404) (3d30cf1)
- batch: put the archived JD after Keyword Coverage in batch reports (#6160) (2287a10)
- browser: share the Chromium executable override across every launch site (#6415) (052ab80)
- cli: infer numeric report number from filepath and extend plugin hook timeout (#6152) (5dbfba0)
- close-stale: close long-silent Applied rows in bulk (#5795) (51a57a8)
- closing-soon: warn when closing dates pile up on an interview day (#5738) (205fed9)
- cover: add the {{RECIPIENT_BLOCK}} slot to the shipped cover-letter template (#5938) (3c44110), closes #5937
- cv: reject stock resume wording the candidate did not write (#6178) (f9ba76b)
- dashboard: y copies the selected application's CV PDF path to t& (#6186) (1bbc30b)
- doctor: warn about user templates that no longer resolve or have drifted (#5957) (5562051)
- expand: propose updates for named repos with new GitHub activity (#5677) (#5680) (f8a8aeb)
- expand: read READMEs of allowlisted private repos through gh (#5426) (#5427) (41585db)
- interview: carry interviewer-stated role priorities into the next round (#5801) (eeb9865)
- interview: classify interview panelists from invite text (panelist-roles.mjs) (#5799) (fc137fd)
- invite-match: draft a pre-interview clarification email for invites (#6100) (960cdd5)
- invite-match: extract interview constraints (no-ai, recording, camera, panel...) (#5734) (3e7818c)
- jd: read UltiPro JDs from the record their page embeds, without a browser (#6245) (d7392c7)
- keyword-match: score CV against a posting URL (#6191) (2024a49)
- linkedin: paste job alerts without a Google account (#6096) (5f96824)
- oferta: advisory role-clarity check and ask-before-you-commit draft (#6095) (91cdce9)
- pdf: read the CV page budget from config/profile.yml (#6325) (#6328) (daa4a7e)
- pdf: warn when CV headline or PDF filename exceeds 64 characters (#5630) (e843469)
- plugin: add a thin plugin for the Antigravity Marketplace (#6335) (086d8c3)
- plugin: add a thin plugin for the Claude plugin directory (#6308) (31906c1)
- plugin: add a thin plugin for the Cursor Marketplace (#6330) (681608b)
- plugin: add a thin plugin for the OpenAI plugin directory (#6323) (74e6a2a)
- plugin: fill the Claude plugin directory listing fields (#6316) (f1e562b)
- privacy: add candidate contact redaction filter for LLM evaluator prompts (#2427) (fc774c7)
- privacy: block protected PII in outbound LLM requests (#5571) (f637363)
- providers: add a generic WP Job Manager job_feed provider (#5878) (bdc837d)
- providers: add apple (reads the server-rendered results page) (#5496) (e32a695)
- providers: add Bulldogjob (bulldogjob.pl) job board (#6253) (6f2d4cf)
- providers: add ClearCompany careers API provider (#5918) (fea7d9b)
- providers: add Darwinbox careers provider (#6416) (5a2df0e)
- providers: add deel provider for jobs.deel.com tenant boards (#6189) (5e67cd5)
- providers: add GermanTechJobs board-wide RSS provider (#6346) (938ee3d)
- providers: add Homerun per-tenant Atom feed provider (#5785) (53c905e)
- providers: add jobs.cz and prace.cz keyword-search providers (#5631) (9b4be8c)
- providers: add Keka careers provider (#6199) (a149e44)
- providers: add Notion careers-page provider (#5616) (192766e)
- providers: add Paylocity provider and scan:full source (#5687) (4b53e0e)
- providers: ApplicantPro / isolved Talent Acquisition (#6252) (2a25b46)
- providers: join and getro cache board ids through a shared cachedLookup helper (#5826) (3d70a5c)
- providers: let an eightfold entry opt in one branded API host (#6000) (9ed1627)
- providers: read careers sites hosted on Factorial's ATS (#6394) (15622c8)
- providers: read careers sites hosted on Factorial's ATS (#6394) (3089d5e)
- providers: read Zucchetti InRecruiting career pages (#5984) (f75baa8)
- reports: write the Machine Summary as the last report section (#6157) (89cccea)
- salary-gap: add third-party advertised source for unverified estimates (#5742) (6341b1f)
- scan-ats-full: sweep join.com from its company sitemap, with a provider id cache for the join company id (#5767) (63030d5)
- scan: let a portals.yml entry set its own skip_tiers (#5806) (2d6ed58), closes #5778
- scan: optional years-of-experience filter read from the JD (closes #6153) (#6154) (0c4b1e7)
- templates: look up named templates in the data root's data/templates (#5952) (7cb0a02)
- verify-pipeline: print a one-line fix hint under every error and warning (#5798) (c7983bc)
- web: undo a Skip or Applied from the Today decision cards (#5769) (47f236f)
- zoho-recruit: accept Zoho regional domains (.ca, .eu, .in, .com.au, .jp, .sa, .com.cn) (#6003) (7d68449)
Bug Fixes
- add-entry: serialize confirmed additions before reading user files (#5915) (9209b95)
- added md files for portuguese(brazil) (#6418) (eb0fffe)
- agent-inbox,apify: stamp the local clock, not UTC (#6212) (8fecd51)
- arbeitsagentur: make angebotsart configurable so Werkstudent/Praktikum searches return results (#5788) (652045a)
- avature: accept query-style /JobDetail?jobId= links (#6477) (d5873cc)
- batch-tailor: run an npm-installed claude on Windows (#5919) (5acc4e7)
- batch: call log_discard on every skipped state, so the discard log is written (#6450) (1068e73)
- build-cv-html: escape braces so candidate text never fills as a placeholder (#5907) (83db42a)
- build-cv-html: read a relative profile photo from the data root (#5909) (dcc2437)
- build-cv-html: warn when the chosen template has no slot for a populated section (#5908) (ed2bf72)
- check-jd-archive: reject every localized template placeholder, not only the English one (#5926) (33fc7d0)
- check-liveness: --status selects the rows it names, or stops the run (#5893) (3be8310)
- clean-markers: keep the joiners emoji, Persian and Indic text need, behind --keep-script-joiners (#5268) (#6267) (87bd659)
- cli: handle --flag=value form in discover-new-companies, company-funded, prepare-application (#5851) (f5f867b)
- cli: handle --help and -h in fetch-jd and seed-fixture (#5822) (9329b08)
- cli: read --flag=value and reject unknown flags in tracker-sync-check and discard-analytics (#6210) (58d6190)
- close-stale: a skip gate that cannot be read is not a gate that passed (#5829) (e71d9b4)
- close-stale: skip rows when the interview company differs by a legal suffix (#6007) (ab65154)
- contact-extract: date a saved contact with the local day, not UTC (#5864) (b4ef324)
- contacts: keep Unicode composition variants on one UID (#6155) (38dedab)
- contacts: update the authoritative duplicate row (#5434) (81270ef)
- cover: report every unresolved {{&}} token, not only UPPER_SNAKE& (#6382) (6be10b2)
- cover: run a letter through the text pass a CV gets (#6361) (1efc58e)
- cover: surface template resolution errors instead of rendering t& (#6383) (bacd824)
- cover: validate required string fields are non-empty strings (#6372) (#6385) (74edf93)
- cv-facts: match titles against the ATS-normalized glyphs (#6358) (e02e8b3)
- cv-order: read a month range in one year from its first month (#6344) (8ac9c33)
- cv-structure: a payload that matches nothing in cv.md is unverified, not passed (#5888) (c4ef01d)
- cv-sync-check: match profile field values, not strings in comments (#5746) (bdddd8a)
- cv-visual: retry the snapshot apt fetch and fail on the real error (#6018) (282b2a0)
- cv: keep Han characters in the PDF text layer (#6184) (86979c5)
- cv: preserve source payloads on aliased render output (#5527) (5dfd45c)
- dashboard: a "^T" or "N/A" URL cell is not a posting URL (#5872) (3d61dd0)
- dashboard: colour each fit-quality slice by its tier, not its position (#5874) (5d39900)
- dashboard: cut a long TL;DR by characters, not bytes (#6367) (fbea51a)
- dashboard: fit the pipeline to the terminal width (#6050) (7d3f0cd)
- dashboard: give unknown statuses their own pipeline tab (#6142) (01def0e)
- dashboard: no average score in the headers when nothing is scored (#5885) (b31289c)
- dashboard: size the tracker row guard from the header, not a fixed 8 (#5873) (559b58e)
- dashboard: sort Hired first in the grouped view, as its group order says (#6304) (19af0ef)
- dashboard: state the Go minimum go.mod actually requires (#6279) (f7c7ea7)
- dashboard: strip terminal controls from tracker and report text (#6049) (951b37c)
- dashboard: the POSTED column counts local calendar days on the dashboard's clock (#5884) (7373924)
- dashboard: truncate preview TLDR to terminal width (#6470) (8e318c4)
- dedup: carry a posting URL the kept row lacks over from the removed row (#5881) (75cfdea)
- dedup: promote a status without its bold or date, so the ledger reads it (#5859) (a46e314)
- dedup: read a row's posting URL from its report when it has no URL cell (#5855) (46a6ad2)
- detect-reposts: count a repost only when the same source re-lists the role (#6165) (02718c0)
- digest: say an empty roll-up is interview notes, not a scan (#6110) (92d5fe7)
- discover-ats: retain concurrent portal additions (#5463) (3346f40)
- distinguish duplicate openings by requisition ID (#6242) (a309ccf)
- do not treat 1C ERP brand as a fabricated workflow count (#4840) (fef0e2a)
- docs: point README customization at modes/_profile.md (#6039) (c7a2e3c)
- docs: show the arguments coverage-check requires (#6047) (d8610f5)
- doctor: do not assume claude when other CLIs are on PATH (#6044) (d6861bb)
- doctor: read plugins from the checkout, not the data root (#6098) (5584f44)
- doctor: stop naming the legacy Gemini CLI as ready to open (#6051) (8d0cfaa)
- eval: pass modes/_custom.md to the standalone evaluators (#5754) (dbdc70c)
- eval: read bolded summary keys and skip the tracker row without one (#6332) (6f83274)
- fact-gate: read French counts in generated CVs and cover letters (#5725) (e5d0596)
- facts: bound address scans on long non-address tokens (#5435) (f5679b6)
- followup-cadence: resolve repo-root report links (#6124) (d071bf6)
- followups: grant the headless sweep the tools it needs to write drafts (#5660) (68964db)
- followups: list the most overdue follow-up first within each urgency (#6073) (c75b240)
- followups: run the sweep script with bash, so the cron recipe works without zsh (#5653) (5fed15c)
- funnel-velocity: measure a re-application from its own Applied date (#5708) (5a820dd)
- funnel: drop follow-up nudges from report summaries when follow-ups are off (#5710) (4786a2f)
- funnel: drop retracted status-log transitions from stage recovery (#5706) (2486afe)
- generate-pdf: check facts against the cv.md this render reads (#5867) (54bf9cd)
- getro: do not stop the walk at an old featured pin (#6406) (f2f0a72)
- hackernews: prefer the posting link over the first URL in a comment (#5784) (61f1afa)
- hired-share: select rows with the canonical parser and exact state match (#5573) (0561e13)
- html-to-text: a prose
<after decoding is text, not a tag (#5868) (12f8641) - i18n: name the sources in localized exclusivity rules (#2395) (#6259) (9a6160c)
- i18n: sync Korean pipeline mode with canonical pipeline.md (#5964) (24e8a9c)
- icims: read location labels that start with Location (#6130) (7a2abd5)
- ics-interview: convert a Windows zone name through the file's VTIMEZONE (#6241) (6b9a6f9)
- ics-interview: give no Scheduled row for a cancelled invite (#6240) (eaa96bc)
- ics-interview: resolve DST transitions according to RFC 5545 (#5914) (dd54193)
- image-pdf: reserve output unless overwrite is explicit (#5443) (ed496f2)
- intake: reject unknown flags instead of scanning (#6041) (c57ac01)
- interview: name --app in debrief Step 10 (#6318) (2efba39)
- jd-skill-gap: "Basic/Minimum Qualifications" headings scanned zero skills (#6255) (#6257) (05ae8c2)
- jd-years: a line holding only a bullet marker is not a heading (#6302) (a86398e)
- jobicy: decode HTML entities in the feed's text fields (#6492) (25846c9)
- jobvite: fold locations that share one posting URL (#6127) (39239c7)
- justjoin: date offers by lastPublishedAt, not the refresh date (#6254) (60ae5e5)
- keep interview dealbreakers out of fenced report examples (#6023) (4105ff7)
- keyword-match: handle backtick-wrapped keywords (#5711) (7cf9f70)
- keyword-match: honor --help and name the report file to pass (#6123) (20b9fd3)
- latex: honor page_format instead of hardcoding letterpaper (#6345) (3462740)
- latex: preserve CV bytes when patch writes fail (#5747) (93e04d6)
- lever: keep a remote workplace on the location (#6138) (755c1b8)
- liveness: --discard-expired closes a row only on closure evidence (#5852) (b61da4f)
- liveness: a short page with no closure evidence is uncertain, not expired (#5999) (e342807)
- liveness: add an UltiPro rung, so closed postings read as expired, not uncertain (#6090) (ee0b5fb)
- liveness: an HTTP 401 or 451 job page is unconfirmed, not expired (#5879) (eb52607)
- liveness: ask VDAB's own API whether a vacancy is published, so closed vacancies don't read as open (#5703) (f4d7477)
- liveness: read Bulgarian Apply buttons, so live dev.bg, zaplata.bg, jobtiger.bg and wherewework.bg postings are not dropped (#6192) (c222283)
- liveness: read the posting's own Apply link in the page header, so Tech in Asia postings are not dropped (#5691) (0292d76)
- liveness: reject unknown flags instead of checking them as URLs (#6086) (6220f54)
- liveness: treat Built In's "Sorry, this job was removed" banner as expired (#6336) (c4b965e), closes #6327
- match-star: read --jd= and --top=, and refuse an unknown flag (#6451) (f328a3f)
- merge-tracker: --backfill-urls fills a "^T" or "N/A" URL cell from the report (#5877) (399e795)
- merge-tracker: --migrate-via labels the header on any recognized layout (#5895) (0e63473)
- merge-tracker: a header without a closing pipe keeps its last column (#5865) (c225581)
- merge-tracker: keep a refused TSV where the re-run it asks for will look (#5862) (1bebf1f)
- modes/tr: write English report header labels and unfreeze is-ilani.md (#3828) (#5845) (7d2588a)
- modes: ask for the Machine Summary in the ar, ja, tr, zh and zh-TW templates (#6161) (ac5e06a)
- modes: bring eleven localized evaluation modes to the A-H report structure (#5843) (#5844) (23dc064)
- modes: embed the ATS keyword coverage block in six localized evaluation modes (#5923) (#5924) (2340792)
- modes: pass posting values to archive and keyword commands as argv, not shell text (#5853) (#5927) (78af0e3)
- modes: save application answers only to the report of the posting on screen (#5854) (#5922) (faa9671)
- modes: trigger Writing Style calibration from cover and email (#5958) (c5f227d)
- modes: use {company-slug} throughout the Turkish evaluation mode (#6029) (#6032) (b31050f)
- openai-eval: record the evaluation's token usage from the stream (#6331) (3e19b86)
- openai-eval: send the session and user-agent headers OpenCode Go asks for (#5825) (adaa6aa)
- openrouter-runner: raise model timeout from 15 s to 120 s (#6017) (af40fc4)
- openrouter: don't save or mark done a posting that wasn't read (#5814) (c61cd38)
- openrouter: improve evaluation reliability (#6027) (20c5bb0)
- openrouter: tell the model it has no tools (#5809) (#5817) (75ea69f)
- outcome: key the posting archive by report number and read the URL column (#5882) (4f09d9a)
- outcome: never record an outcome on a row the selector does not name (#5861) (08c0770)
- patterns: a via channel nothing went through has no advance rate (#5886) (9d94b41)
- pdf: honor PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH and document macOS fallback (#6209) (4d9bbd2)
- pdf: isolate shared painters by workspace context (#6164) (1c5fc5a)
- pdf: replace the shared browser after disconnection (#6163) (2622650)
- pdf: resolve relative paths against the workspace (#6082) (1b0567b)
- pipeline: process the CAREER_OPS_PIPELINE lane's inbox, not data/pipeline.md (#6412) (6a3be78)
- plugins: honor CAREER_OPS_PIPELINE when de-duplicating ingested leads (#6378) (75a2f59)
- plugins: prevent unbounded memory growth on large plugin responses (#6366) (84ef4dd)
- plugins: refuse the same addresses as the provider IP guard (#6271) (14b0ce6)
- plugins: reject unknown flags and honor help and registry names (#6097) (3877747)
- plugins: ship the template skill as skill.md.template so catalogs do not list it (#6171) (d5ac1a4)
- plugins: stop listing plugins when plugins.yml will not parse (#6117) (f85d3e5)
- plugins: stop waiting on a DNS lookup that never answers (#6404) (c514700)
- portals: repoint example boards that went empty or were disabled after a move (#6393) (8b09cbd)
- pracecz: enforce hard max pages cap (#6401) (d7bd1d6)
- precheck-duplicate: match separator-less req IDs and location-suffixed titles (#5998) (69b144d)
- prefer MiniMax Flash in text evaluation (#5531) (a935197)
- prepare-application: accept inline URL arguments (#5850) (98f86ce)
- prepare: accept canonical Greenhouse job board hosts (#6025) (920ce05)
- prepare: read the candidate block in profile.yml (#6083) (5faf024)
- profile: reject spend tier, language, and CV format values readers ignore (#6119) (3ca13e3)
- providers: allow credentialed HTTP proxies on loopback under trusted egress (#5529) (#5819) (b6b9e38)
- providers: arbeitsagentur home-office filter, remote marker for 100 % home office, all posting locations (#6006) (1b99405)
- providers: arbeitsagentur links and liveness for reference numbers with a slash (#6499) (ec496f0)
- providers: cap fetchJson/fetchText response bodies (#5575) (e0a243a)
- providers: cap, pace and retry IBM pagination (#6273) (bfe8b2c)
- providers: emit postedAt from remoteok, remotive, workingnomads and ibm (#6274) (3230f0c)
- providers: getro warning names the failed page and the real attempt count (#6465) (7be575f)
- providers: give the dover health probe a no-retry policy (#5990) (f73af7b)
- providers: give the himalayas health probe a no-retry policy (#6008) (f24662e)
- providers: join reads jobs from the public GraphQL list instead of the cached careers page (#5753) (0abe42c)
- providers: read Greenhouse and Ashby board slugs from the parsed careers_url (#5880) (e1c8565)
- providers: say when a blocked host looks like a DNS filter or sandbox (#5810) (74467b7)
- radancy: read a bare location class in the legacy markup (#5824) (d3fd0f7)
- rank: preserve the pipeline when saving annotations fails (#5716) (f853f7d)
- rank: run npm-installed agent CLIs on Windows (#5787) (1a03532)
- registry: update Tavily plugin to v0.1.1 (#6348) (ea096c4)
- registry: update Tavily plugin to v0.1.2 (#6461) (5e00aab)
- rejection-latency: match the interview company across legal forms (#5987) (f25b714)
- rejection-latency: the CLI counts from the local day, not the UTC day (#5863) (c092341)
- reserve-report-num: never hand out a tracker number the ledgers still name (#5655) (9f1913a)
- salary-gap: keep the sample size beside each per-currency mean (#5910) (3c088c5)
- scan-ats-full: --resume after an outage stop no longer saves its matches twice (#5871) (e443613)
- scan-ats-full: a malformed --limit is a usage error, not an unbounded sweep (#5889) (4331b1d)
- scan-history: a Dayforce content, visa or country cut no longer pins its URL (#5869) (89e3095)
- scan-history: every reader keeps the first row of a headerless file (#5892) (3f3a8a8)
- scan-hn: one hn_hiring keyword written without brackets still filters (#5890) (4b9c53c)
- scan-hn: record an HN post's own date, not the scan date (#5891) (62e35a7)
- scan-interamt, scan-dayforce: record each skipped posting once per status, not once per run (#5904) (e642cc5)
- scan: a portals.yml entry can raise the response size cap with max_response_mb (#6009) (674c804)
- scan: deduplicate an unnamed employer's posting by URL, not ::title (#5866) (bc04629)
- scan: exit 2 when every target failed (#5720) (965681c)
- scan: reject a misspelled portals.yml key (#6107) (32863fd)
- set-status: match a company when only the legal suffix differs (#6043) (7b8e9d2)
- set-status: name the tracker path a first evaluation creates (#6045) (a6d7526)
- set-status: reject a list of tracker numbers with the one-row commands (#6042) (c551197)
- skill-gap: recognize Spanish requirement headings and CV sections (#5664) (7aaa6f7)
- skill: guide a skill installed without career-ops to an install (#6172) (d8adac8)
- skill: list every routed mode in the discovery menu, and call oferta A-H (#6215) (a0748a0)
- smartrecruiters: read releasedDate into postedAt so the age filters apply (#6303) (77d1114)
- stats: count only enabled portal entries in the configured denominator (#5715) (f640ded)
- stats: drop the cold breakdown from --summary while follow-ups are off (#5899) (eb76a1c)
- stats: print the denominator the portal coverage percentage divides by (#5898) (a5885eb)
- status-hooks: an Applied follow-up pin honours CAREER_OPS_FOLLOWUPS (#5883) (e1988a3)
- status: report the detached archive runner's pid; test the bound through it (#5931) (#5932) (e7d139a)
- status: start the detached JD archive without a console window on Windows (#6004) (fe7fb6a)
- status: strip a date from a status cell however it is written (#5860) (688f3a6)
- strip ANSI codes from Playwright error messages (#6185) (c839c85)
- successfactors: drop a trailing comma on a location (#6139) (c3f06cb)
- sync-batch-input: refuse unknown flags and read --flag=value (#6343) (c423da8)
- templates: honor profile font_family in the Arabic CV block (#6431) (7d8feb6)
- templates: T1 encoding so the LaTeX CV text layer keeps _ and ~ (#6443) (e59bc59)
- test-all: report a node:test suite killed for time as killed, not exit ? (#5812) (0f322bd)
- tests: name the data root in apply-scope instead of clearing it (#6290) (2cc4a59)
- tests: require the intended rejection, not just any failed run (#5577) (d9502be)
- tests: resolve a PATH-found bash to its absolute file before caching (#5896) (a7677d8)
- tracker-parse: read a req id behind an id-parameter name (#5782) (7e3fcb7)
- tracker-sync-check: prefer the one exact role match at the same employer (#5988) (599536b)
- tracker: accept a bare tracker number in history (#6040) (61906d2)
- tracker: build a new index's schema in one transaction (#6456) (d430f83), closes #5514
- tracker: keep a balanced closing paren on a report URL token (#5581) (9ee1bff)
- tracker: keep historical numbers out of new merges (#5980) (ea9c129)
- tracker: list every subcommand's flags in top-level --help (#6035) (866e2a3)
- tracker: match a company query when only the legal suffix differs (#6087) (924090a)
- triage: skip a posting that says it was removed (#6414) (13f03cc)
- validate-profile: read --profile=path, reject unknown flags and a missing explicit profile (#6211) (825192c)
- verify-cv-facts: do not require a source for a number about the addressed employer (#5936) (9fce9d6)
- verify-cv-facts: keep hyphenated words in claims (closes #5632) (#5792) (6b11499)
- verify-cv-facts: read an employer named by "at , I ..." (#6380) (5264751)
- verify-cv-facts: refuse a --source that does not exist (#5887) (ef89108)
- verify-pipeline: don't flag anonymous rows from different agencies as duplicates (#6070) (70dc44f)
- verify-pipeline: honour --help and refuse unknown flags (#6342) (3e60bda)
- verify-portals: probe Lever and Ashby boards with their provider's timeout (#6507) (580e1fd)
- web: declare the full NODE_ENGINES range in web's engines (#5993) (5ba0cda)
- web: state the project Node floor (22.13) in web's engines (#5928) (3f7a280)
- workday: keep a fully remote workplace on the location (#6143) (2665a93)
Performance Improvements
- check-liveness: import playwright only when a URL needs the browser (#6056) (a15cc12)
- dedup: build company and posting keys once per row (#6094) (91a1fd6)
- pdf: paint a batch of PDFs with one browser (#6106) (dd0eb97)
- scan-history: parse history lines without building pair arrays (#6055) (498bf8e)
- scan: reuse a board response from the last 15 minutes and recheck older ones with ETag (#6105) (7bd516b)
- verify-ats: keep the style scanner linear without per-char allocation (#6442) (6452019)
web: 0.17.0
0.17.0 (2026-11-05)
Features
- apply: upload the tailored CV under a recruiter-facing file name (#6399) (#6478) (a889bff)
- cv: reject stock resume wording the candidate did not write (#6178) (f9ba76b)
- linkedin: paste job alerts without a Google account (#6096) (5f96824)
- reports: write the Machine Summary as the last report section (#6157) (89cccea)
- scan: optional years-of-experience filter read from the JD (closes #6153) (#6154) (0c4b1e7)
- web: choose full or focused job evaluations (#5917) (5cc2b21)
- web: import PDF and TeX CVs from the editor (#6238) (d0a1dfe)
- web: jump to any page or application with Ctrl+K (#6084) (c45f766)
- web: save a pipeline view, including a score floor (#6103) (34bff2e)
- web: set tracker status from the keyboard (#6102) (2a80eb4)
- web: show a tailored-resume column in the Pipeline table (#6341) (3604713), closes #6338
- web: skip and save inbox rows from the keyboard (#6101) (917d60b)
- web: undo a Skip or Applied from the Today decision cards (#5769) (47f236f)
Bug Fixes
- followups: list the most overdue follow-up first within each urgency (#6073) (c75b240)
- modes/tr: write English report header labels and unfreeze is-ilani.md (#3828) (#5845) (7d2588a)
- rank: run npm-installed agent CLIs on Windows (#5787) (1a03532)
- remove evaluated jobs from the pending inbox (#5906) (b911da4)
- web/explore: preserve posting dates when adding to pipeline (#5690) (b326f22)
- web: a breakdown bucket nothing was submitted from shows no conversion rate (#5875) (1366774)
- web: add a Skip to content link for keyboard users (#6063) (0c91005)
- web: announce why an analytics rate shows a dash (#6239) (d71716f), closes #5969
- web: count CV preview pages from the content (#6180) (2a0e05e)
- web: darken light-mode status text so it clears WCAG AA (#6078) (8629c18)
- web: declare the full NODE_ENGINES range in web's engines (#5993) (5ba0cda)
- web: disable automatic agent-rules generation in next.config.mjs (#6150) (6e795a7)
- web: do not cache a failed logo lookup as a permanent miss (#5903) (60b8800)
- web: do not flag an empty install as a CV with no skills (#6046) (d02c718)
- web: explain a missing portals.yml before the health check (#6109) (ba97fbe)
- web: hide Config choices that do not work yet (#6122) (f76924d)
- web: keep CV edits and show when they are saved (#6179) (e922a6e)
- web: keep cv preview header lines on their own lines (#6068) (1bf9bb9)
- web: keep empty tracker copy when filters are active (#6298) (47f33a0)
- web: keep pipeline and follow-up search in the URL (#6060) (3f409aa)
- web: keep profile.yml comments on profile and cadence saves (#5678) (95813f3)
- web: keep the app shell on unreadable and missing reports (#6075) (5e2c28f)
- web: keep the example person out of a first profile (#6359) (480b44b)
- web: keep the follow-ups table in place while the cadence loads (#6074) (91fb762)
- web: keep the last CV Studio edit when you leave (#6182) (444d4e8)
- web: keep your place when a Pipeline back link returns to the list (#6072) (dc2e2b7)
- web: launch every remaining web child process without a console (#5902) (b802349)
- web: launch the six analytics routes with process.execPath and windowsHide (#5900) (91d0d07)
- web: lead Today with the queue once there is work (#6114) (0a87359)
- web: never overwrite an unreadable modes/_profile.md with a stub (#5839) (824dc51)
- web: offer Generate when a marked CV has no file (#6116) (ef9006f)
- web: onboarding offers the assistant only when a CLI can run (#6432) (5236b3a)
- web: open CV Studio on the row's own report, not the row number's (#6340) (1772d4b)
- web: paint brand text with the brand-text token (#6081) (de1ab91)
- web: persist the Config CLI pick from an effect, not the setCliId updater (#6034) (2d6d83b)
- web: pin the Homebrew opt path in the scan schedule so brew upgrade does not break it (#6375) (907422a)
- web: print reports without app chrome, collapsed sections or dark text (#6067) (3e0d298)
- web: read Node's bracketed error code as a scan failure cause (#5996) (4814e80)
- web: read report headers saved with Windows line endings (#6052) (19f1826)
- web: recognise Chinese legitimacy tiers in the apply line and badge tone (#5925) (7383ee7)
- web: refresh config consumers after same-tab saves (#5807) (a66df7f)
- web: refresh documents when job completes (#6435) (0184805)
- web: refuse a cadence save from a tab that loaded an older profile (#6053) (7b517c5)
- web: remove the grey strip on the right edge of every desktop page (#6064) (53604f6)
- web: render CV studio preview markdown inside the page (#6181) (6292c19)
- web: resolve custom CV templates from data root (#6324) (74054e6)
- web: resolve the A-H evaluation modes of modes/sg and modes/vi (#5707) (0f8f93a)
- web: run core scripts and read system files from the checkout, not the data root (#4430) (c6fec47)
- web: show a second posting with the same title in What's New (#6148) (f421868)
- web: show Open on the follow-up report link (#6120) (b74dbbf)
- web: show the quality-threshold reasoning when the core recommends no cutoff (#5876) (43066a4)
- web: show unknown statuses instead of counting them as evaluated (#6129) (6b2507a)
- web: show what the tracker search filtered and how to undo it (#6065) (7396388)
- web: state the project Node floor (22.13) in web's engines (#5928) (3f7a280)
- web: tell an empty tracker apart from a search with no matches (#6054) (3e5df61)
- web: title the empty Documents page and name the next step (#6121) (148be0f)
- web: treat a non-JSON rewrite response as a failed rewrite (#6405) (202befe)
- web: treat a one-job CV as ready and lead first-run with setup files (#6118) (0ce892e)
- web: use the visible label as the accessible name (#6080) (445c0d3)
Performance Improvements
- web: keep one browser for dashboard PDF export (#6177) (7915e6e)
- web: load the assistant's markdown renderer only when the console opens (#6059) (5f2824c)
- web: send Explore only the fields it matches on (#6089) (91be704)
- web: stop re-reading the tracker for every row on Search stats (#6066) (f69babb)
Sponsors
SerpApi sponsors career-ops through its fiscal host, Open Source Collective.