This release is about getting through the filter: eight more places to find openings, and a CV that applicant tracking systems read the way you wrote it.
Highlights
- Eight new job sources. ADP Workforce Now, Dayforce, Taleo and UKG Pro by @Schlaflied (#3729, #3734, #3743, #3733), JazzHR by @ilyakanevskiy (#4307), Gupy by @felipe-NR (#4550), startup.jobs by @phozzy (#4704) and PageUp by @williamchong (#4693). Eightfold boards now return their jobs instead of zero, by @kellymmcgrath (#4297).
- A CV the ATS reads correctly.
pdf --atswrites a plain ATS variant next to the styled CV, by @vliggio (#4909).atsLintchecks a template against ATS rules kept as data intemplates/ats-rules.yml, by @rubicon (#3900). A CV structure check by @euskode (#3472), a title-consistency check by @Schlaflied (#2678), and a flag for inflated scope verbs and unsourced adoption claims by @MannXo (#3784). Hyphenated terms like "go-to-market" no longer split across lines in the PDF, by @Kevin-Boyle (#4911). - More markets. A Singapore market mode by @jpelaez-23blocks (#4687), and
language.modes_dircan now list several markets at once, by @Schlaflied (#3798). - The web dashboard. Local scheduled scans by @aselekoglu (#2628), Analytics progress and insights read from the core by @abankar1 (#4576), and assistant conversations that keep their earlier context by @luochen211 (#4495).
- Optional GDPR consent footer for CVs (
{{CONSENT}}), by @drawski (#4286).
Your agent offers this update at the start of your next session. If it doesn't, run this once in your career-ops folder:
node update-system.mjs apply --confirm
Your CV, profile, tracker and reports are not touched.
Thank you
This release carries 211 pull requests from 68 people, 20 of them contributing for the first time.
- @vliggio: #3422, #3765, #3854, #3916, #4737, #4738, #4745, #4757, #4760, #4763, #4764, #4781, #4782, #4803, #4880, #4888, #4889, #4894, #4897, #4898, #4904, #4906, #4909
- @luochen211: #4374, #4381, #4445, #4452, #4494, #4495, #4500, #4640, #4641, #4643, #4644, #4647, #4648, #4669, #4670, #4733, #4740, #4741, #4742, #4762, #4865, #4869
- @Schlaflied: #2678, #3700, #3729, #3733, #3734, #3743, #3798, #3912, #4016, #4363, #4524, #4527, #4528, #4535, #4536, #4692, #4696, #4749, #4751, #4826
- @rubicon: #3653, #3900, #3904, #3905, #4008, #4069, #4094, #4403, #4404, #4406, #4412, #4533, #4567, #4651, #4800, #4802
- @abankar1: #3985, #3993, #4540, #4542, #4544, #4546, #4548, #4576, #4586, #4767
- @artemtrofymenko: #4511, #4519, #4739, #4747, #4756, #4779, #4806, #4814, #4884, #4892
- @ilyakanevskiy: #4307, #4569, #4613, #4633, #4711, #4714, #4778, #4790, #4804
- @roydonsequeira (first contribution): #4725, #4726, #4755, #4761, #4771, #4810, #4833
- @IaroslavMazur: #3304, #4195, #4321, #4666, #4671
- @Kevin-Boyle: #4821, #4823, #4900, #4911
- @maxmilian: #4563, #4699, #4815, #4863
- @Wizarck: #3789, #4705, #4706, #4707
- @felipe-NR: #4549, #4550, #4846
- @KusalPabasara (first contribution): #4688, #4744, #4746
- @MdRaf1: #4715, #4716, #4723
- @pmgwee: #4338, #4473, #4701
- @ronanime-arch: #4346, #4409, #4697
- @williamchong: #4689, #4690, #4693
- @AdilAzhariOmsan: #3522, #4638
- @jpelaez-23blocks (first contribution): #4686, #4687
- @kellymmcgrath: #4076, #4297
- @miteshanshu (first contribution): #4728, #4807
- @nikolaysm: #3716, #3947
- @phozzy (first contribution): #4704, #4765
- @sloemo01: #4333, #4341
- @SulimanAbdulrazzaq: #4885, #4912
- @Zoubeir23: #4214, #4557
- @aselekoglu (first contribution): #2628
- @badukucuk (first contribution): #4791
- @Bekon0700: #4685
- @brian8759 (first contribution): #4730
- @davidnunez: #2739
- @DennyHo0917 (first contribution): #4664
- @drawski (first contribution): #4286
- @egurnov: #4774
- @euskode: #3472
- @gunjanjaswal: #3191
- @huiq777 (first contribution): #4678
- @idontwannarock (first contribution): #4663
- @jduffey1990: #4817
- @MadhurJ10 (first contribution): #4812
- @MannXo: #3784
- @mbrow190: #4107
- @mkriegl: #4617
- @mrbese: #4703
- @nikitacometa: #3834
- @obielin: #4684
- @peterbussch: #4428
- @prasta1: #4851
- @pwilinchery: #4302
- @rahulnainala (first contribution): #4673
- @readyagentsdev (first contribution): #4677
- @SamanPandey-in: #4847
- @samintisar: #4578
- @santichausis: #4659
- @scs0209 (first contribution): #4792
- @sghanna (first contribution): #4770
- @Shaamak: #3898
- @sonukhobragade: #2760
- @Souptik96: #4368
- @SparshGarg999: #4088
- @sundarshankar: #4102
- @SunilKumarPradhan (first contribution): #4813
- @tahakotil (first contribution): #4661
- @TianHengZhuang: #4878
- @WJiangH: #2690
- @ybai08: #4672
- @Yi-111-a (first contribution): #4635
1.36.0 (2026-10-10)
Features
- ci: fail a PR while a dependency it names is still open (#4403) (71bb57d)
- contacto: surface saved internal-referral contacts before cold search (#4692) (3957d70)
- contacts: extract a recruiter/interviewer contact from a pasted reply (#4363) (1934b3e)
- cv-facts: flag scope-verb inflation and unsourced adoption claims (#3784) (06f6452)
- cv-templates: add atsLint, with the ATS rules as data in templates/ats-rules.yml (#3900) (6f1a74e)
- cv: add opt-in GDPR consent footer slot ({{CONSENT}}) (#4286) (5c0e765)
- dashboard: open the job posting from the report viewer with
o(#4821) (024f059) - discover-ats: flag resolved boards with very few postings (#4869) (8af2aef)
- explain evidence confidence behind evaluation scores (#4452) (1a9a76b)
- gojobs: add offline GO Jobs HTML import (#4016) (d35cf64)
- i18n: report structural drift across translated modes (#4643) (a8a71f5)
- i18n: support language.modes_dir as a list of declared markets (#3798) (d31a138)
- liveness: read Workday's 403 S22 as a withdrawn posting (#4633) (23a8ecf)
- local-parser: pass a parser's extra job fields through (#3438) (#4697) (034ca77)
- modes: add Singapore market mode (modes/sg/) (#4687) (963d8bf)
- oferta/apply: surface fixed-term contract duration at apply time (#4535) (a156d4d)
- patterns: close the discard_reasons vocabulary (#4549) (f14202f), closes #2785
- pdf: add CV structure check; land as a warning per maintainer feedback (#3472) (f6d38b9)
- pdf: opt-in
pdf --atsemits an ATS variant alongside the styled CV (#3853) (#4909) (72650c1) - providers: add JazzHR zero-auth provider (#4307) (a18a644)
- providers: add startup.jobs RSS provider (#4704) (b64b6c3)
- providers: capture the ATS-native posting and requisition ids (#4076) (6b4cd44)
- providers: eightfold reads PCSX tenants instead of returning zero jobs (#4297) (1601693)
- providers: PageUp — vendor-hosted careers sites (#4693) (9493bc8)
- registry: check pins against published releases on a schedule (#4651) (c731c69), closes #4573
- reply-matcher: date-guarded company-wide rejections (#4826) (ccdc4d3)
- salary-gap: relocation purchasing-power comparison (#4694) (#4696) (ef00bb0)
- scan-ats-full: gate boards on domain relevance before title-filtering (#3304) (55694d7)
- scan: add ADP Workforce Now provider (#3729) (b67e254)
- scan: add Dayforce scanner (scan-dayforce.mjs, Playwright-based) (#3734) (b4de1df)
- scan: add Gupy board-wide provider (#4550) (04a80be)
- scan: add Taleo public career-section provider (#3743) (b922c8c)
- scan: add UKG Pro/UltiPro provider (#3733) (76e0616)
- scan: internationalize visa_filter sponsorship vocabulary (#4686) (c73574a)
- scan: let a target declare which field its whitelist reads (#3438) (#4346) (4df96ab)
- scan: record what the location and posting-age filters drop (#4321) (b17e77c)
- scan: seed ATS sweep from application history (#3912) (43910e4)
- scan: SmartRecruiters requisition ids and opt-in language-aware dedup (#4613) (f3846b0)
- session-activity: advisory in-progress claims for concurrent sessions (#4536) (b02a8d6)
- set-status: archive the JD automatically on the transition into Interview (#4524) (c3b501a)
- templates: let a template pack declare the sections it owns (#3852) (#3916) (261d3c5)
- templates: opt-in project_break_inside, for the one-word widow above a tech line (#4723) (023558e)
- tracker: fix-report-links.mjs repairs rows whose report link is dead (#4750) (#4751) (24745c5)
- tracker: render the URL column as a markdown link (#3516) (#3854) (c5e1c4f)
- verify-pipeline: surface check-jd-archive.mjs's findings as Check 17 (#4527) (9fd8747)
- web: add local scheduled scans (#2628) (85b67f5)
- web: Analytics progress + insights views, read from the core (#4576) (2d38488)
- web: preserve assistant conversations and earlier context (#4495) (f9e9139)
- web: surface post-interview silence on the Follow-ups page (#4586) (9f0b533)
- zero-LLM CV title-consistency check for pdf.md tailoring (#2678) (9f0eec7)
Bug Fixes
- agent-docs: align API-first verification and CLI-only script checks (#4779) (9644e28)
- agent-inbox: number resolve against file position, not the pending view (#2739) (93fd89a)
- agents: scope onboarding and keep diagnostics read-only (#4428) (2aeb555)
- apply: source form fields from the tailored CV instead of cv.md (#4412) (c2681c6)
- archive-posting,application-answers: date records by the local calendar (#4544) (ec16f68)
- archive-posting: refuse to save a non-content capture (login wall/404/paywall) (#4528) (91d7df9)
- batch: merge into the locked pipeline.md instead of overwriting it with the start-of-run snapshot (#4912) (7fb9437)
- batch: route standard and premium spend tiers to Sonnet 5.5 and Opus 5.5 (#4703) (b4e9a14)
- ci: cover batch/ in the no-user-data guard (#4533) (0e4aeae)
- ci: grant ci-approve.yml the contents: read it needs to check out (#4635) (49d99e4), closes #4616
- ci: no-user-data guard blocks documents/, modes/_brief.md and other drifted user paths (#4891) (#4894) (7c19718)
- cli: merge-tracker.mjs merges for real when --dry-run is mistyped: delegate to lib/cli-flags.mjs (#4678) (4c1a5fa)
- cover: give {{DATELINE}} the date when an address block renders (#4069) (a800863)
- cv-checks: read Pandoc-style cv.md; never ✅ on zero compared (#4879) (#4880) (2b3fb67)
- cv-facts: read a spelled-out magnitude as part of the number (#4878) (ede8fe8), closes #4872
- dashboard: DATE column shows the latest status change, not the eval date (#4817) (8675128)
- dashboard: preserve status lifecycle side effects (#4644) (3c1aebd)
- dashboard: render unevaluated rows as the sentinel, not "0.0" (#2760) (2511791)
- dashboard: show explicit tracker and Notes locations (#4852) (#4863) (38d9fb3)
- dedup-tracker: a posting-URL conflict blocks a merge (#4578) (3688b7f)
- docker: install a Go that satisfies dashboard/go.mod (#4889) (b2d631e)
- doctor: check that each dependency resolves, not that node_modules exists (#4782) (b5e61c4)
- doctor: detect Playwright MCP servers configured in ~/.claude.json (#4563) (47b0d49)
- fetch-jd: read JDs from company-careers gh_jid links and SmartRecruiters (#4673) (350bde3)
- funnel: retain replies and historical stages across surfaces (#4374) (ead56e8)
- gem: fold the isoCountry name into the location string (#4774) (d26fcde)
- generate-pdf: derive workspace root before canonicalizing the tracker (#3169) (#3191) (91ee04c)
- gitignore: ignore the .career-ops-data marker (#4663) (6a9b252)
- gitignore: pair each anchored user-layer rule with a directory negation (#4567) (e6a0933)
- greenhouse: resolve legacy boards.greenhouse.io careers_url (#4195) (5367abb)
- gupy: follow the API to portal.gupy.io and send the filter names it reads (#4833) (b5ba43f), closes #4831
- handle dead postings in batch evaluation (#4381) (bd24097)
- harness: the web-unit batch discards its child's output, so a Windows failure names 100 files and explains none (#4767) (d31844c), closes #4766
- higheredjobs: a walled feed is a named error, not an empty board (#4511) (388bc68), closes #3637
- hired-share,intake: an unreadable state file is not a first run (#4540) (b9ad633)
- hired-wall: require --rebuild or --add before writing (#4896) (#4898) (56f8ddb)
- honor TTL ceiling for advisory session claims (#4740) (07c9bb1)
- keyword-match: find the keyword section under the heading each mode writes (#4725) (bfdcae5)
- keyword-match: match acronym plurals and reach their synonym groups (#4726) (181713a)
- keyword-match: read the ## Extracted Keywords heading batch workers write (#4851) (fd659a7)
- licenses: ship OFL text with bundled fonts and LICENSE with the npm package (#4888) (1adcdfb), closes #4886
- liveness: a banner on its own line is not part of the line above (#4810) (880a1cb)
- liveness: a posting that says how it will close is still open (#4771) (c0264e7)
- liveness: poll the page while it hydrates instead of one read after a fixed 2s (#4804) (95728c6)
- liveness: record the expired verdict so a dead posting stops resurfacing (#3905) (1a68591)
- liveness: retry BambooHR once before calling expired (#4569) (7c81270)
- merge-tracker: an aggregator URL is not a requisition identity (#3652) (#3653) (bdcf7a0)
- merge-tracker: explain a failed report number that a completed row reused (#4519) (b86b33c)
- merge-tracker: warn when a report link points at a missing file (#4749) (c9d88c3)
- node: raise the Node floor to 22.13 and test it in CI (#4801) (#4803) (3b9bd64)
- pdf: keep hyphenated words on one line so the PDF text keeps the term (#4911) (02bd978), closes #4908
- pipeline-lock: make OWNERLESS_GRACE_MS env-overridable, fixing flaky test 16 (#4557) (31005eb)
- pipeline: break sort ties on the row number, so newest-first reorders a date (#4333) (c4f2c3f)
- pipeline: stop retrying unavailable LinkedIn job descriptions (#4641) (a39dc76)
- pipeline: take the pipeline lock in reconcile-pipeline.mjs (#4895) (#4897) (df0d613)
- plugins: resolve user config from data root (#4688) (7ddbd86)
- providers: address post-merge review on startup-jobs (#4765) (08fe5d0)
- providers: amazon lists every city of a multi-city req (#4900) (fb8e232)
- providers: deutschebahn returns 0 postings — an unrenderable db.jobs posting blanks the first score-sorted page (#4714) (40c3739)
- providers: end csod and avature paging on the rows the source returned (#4885) (d52a0e9)
- providers: move //
@ts-checkto line 1 in six providers (#4790) (5062c3e) - providers: pair undici fetch with its proxy agent so trusted proxy egress works on Node 26 (#4812) (cce560f), closes #4808
- providers: skipIds covers an explicit provider: field too (#4884) (acd9d00)
- radancy: read a sibling job-location element in the legacy markup (#4689) (cf31a93)
- reply-matcher: count combining marks when measuring a company name (#4542) (20897ea)
- salary-gap: resolve column 1 as a tracker#, not a report# (#4368) (2fd2ccf)
- scan-dayforce: report interactive challenges as a named error and stop (#4685) (2dede5c), closes #4675
- scan: keep the first row of a headerless scan-history.tsv (#4807) (6554b64)
- scan: make scan-history formula escaping reversible (#4778) (8fae375)
- scan: support trusted proxy egress for provider requests (#4445) (c034621)
- scan: verify offers via APIs before launching Chromium (#4640) (82dd887)
- shared: let _profile.md define the archetypes, and allow "none of these" (#2690) (d4b2f8e)
- skill-extract: count "fine-tuning" only where it names the ML skill (#4761) (23d3457)
- skill-extract: read the other spellings of AI/ML skills a CV uses (#4755) (3bbf2ae)
- skill: route triage, calibrate, intake and ats from the router (#4811) (#4815) (eeede80)
- smartrecruiters: keep the configured slug in fallback job links (#4770) (2877692)
- story-bank: stories an evaluation adds aren't invisible to npm run star anymore (#4684) (2f0e32c)
- story-bank: three readers, three roots — and a safety gate split across two (#3985) (cbae0bd)
- story-provenance: anchor the Provenance marker to the start of its line (#4865) (352e6d3)
- successfactors: resolve a /go/// careers_url to the tenant root (#4659) (4e151da), closes #4655
- templates: keep the contact separator from starting a wrapped line (#4715) (b075484)
- templates: make job_break_inside an opt-in style token (#3789) (dc49e6b)
- test-harness: linkRepoPackage resolves packages the way Node does, so worktrees work (#4781) (356d9d7)
- tests: guard the sandbox node_modules link (#4406) (9085052)
- tests: keep the fresh-install pipeline test out of a real CAREER_OPS_PIPELINE (#4707) (88a2ea1)
- tests: keep the suite out of a real CAREER_OPS_TRACKER (#4892) (f882516)
- tests: skip title-fit when web/ is absent (#4706) (a5e762d)
- title-filter: treat CJK characters as word boundaries for short keywords (#4690) (7d0e312)
- tracker: allow correcting stale notes without hand-editing (#4494) (5385f3a)
- tracker: resolve tracker paths via resolveTrackerPath(DATA_ROOT) across CLI tools (#4087) (#4088) (151be63)
- update-system: exempt a user-configured named template variant from the templates/ prune (#3700) (65ee5ea)
- update-system: insert new gitignore rules before the fixtures negation (#4214) (182c28c)
- update-system: keep protecting a customization an update preserved (#4341) (a395e67)
- update-system: refuse manifest entries that name the user layer (#3947) (625a82c)
- updater: apply updates on main when run from a linked worktree (#4738) (ad66a6a)
- updater: ship user-directory scaffolds safely (#4741) (136e93f)
- validate-profile: commented-out example sections are not unknown keys (#4705) (1d85279)
- validate-profile: read opt-in keys the example ships commented out (#4737) (8dbf0b9), closes #4736
- verify-ats: stop reading a white background as hidden white text (#4802) (6959490)
- verify-cv-facts: do not read standard identifiers as count claims (#4666) (3362de5)
- verify-pipeline: warn about a report that could not be inspected (#4814) (0b07775)
- workable: a posting listed in several countries keeps all of them (#4806) (b07171d)
- workday: collapse the -N disambiguator on a hyphenated requisition base (#3882) (#4409) (6a3e1eb)
web: 0.14.0
0.14.0 (2026-10-10)
Features
- cv-templates: add atsLint, with the ATS rules as data in templates/ats-rules.yml (#3900) (6f1a74e)
- i18n: support language.modes_dir as a list of declared markets (#3798) (d31a138)
- templates: let a template pack declare the sections it owns (#3852) (#3916) (261d3c5)
- web: add local scheduled scans (#2628) (85b67f5)
- web: add route-aware loading feedback (#4338) (e049608)
- web: Analytics progress + insights views, read from the core (#4576) (2d38488)
- web: edit application status inline in Pipeline (#4701) (b89ef7e)
- web: keep context during loading transitions (#4473) (e691fa6)
- web: preserve assistant conversations and earlier context (#4495) (f9e9139)
- web: surface post-interview silence on the Follow-ups page (#4586) (9f0b533)
Bug Fixes
- funnel: retain replies and historical stages across surfaces (#4374) (ead56e8)
- liveness: record the expired verdict so a dead posting stops resurfacing (#3905) (1a68591)
- pipeline: break sort ties on the row number, so newest-first reorders a date (#4333) (c4f2c3f)
- web/apply: never hand the planner a ref to a submit control, and guard every action by element facts (#3834) (a6637dd)
- web: bind the dashboard to loopback by default (#3716) (7062ed5)
- web: confirm paid assistant fan-out with cost estimates (#4746) (b3b62b4)
- web: count cached input in usage meter (#4744) (088d0dd)
- web: fall back from a stale saved cliId on every AI route, not just Run (#4638) (431f593)
- web: pre-fill apply answers from the CV attached to the same form (#4404) (414ff23)
- web: read the whole of modes/_profile.md, not just the managed block (#4008) (f4c52d1)
- web: require confirmed worker stream completion (#4107) (7860d2f)
- web: update vulnerable dependencies (#4670) (077ff80)
- web: validate profile updates before writing (#4500) (b208464)
Sponsors
SerpApi sponsors career-ops through its fiscal host, Open Source Collective.