1.29.0 (2026-08-25)
Features
- anti-fabrication: tier the Source-of-Truth boundary and add story-provenance-check (#2947) (498dd11)
- contacts: linkedin-join.mjs — warm-intro finder from a LinkedIn connections export (ba1a3dd)
- cv: optional url support for projects in HTML and LaTeX (93e256c)
- detect-reposts: skip multi-employer aggregator boards, and say why (d6ac988)
- pdf: declare CV section order in config/profile.yml (#2533) (c90b139)
- providers: add jobbankca, Canada's federal Job Bank (7e9feb4)
- providers: job.description for recruitee, ashby, and opt-in smartrecruiters (#3175) (83d3ac6)
- providers: mycareersfuture, Singapore's national job bank (#230) (a726f53)
- scan: add Hacker News scanner with optional AI enhancement (f93b6e9)
- scan: opt-in anchored keyword matching (82be449)
- verify-pipeline: flag a malformed follow-ups.md instead of reading it as empty (#2971) (a5ffae2)
- web: restrict the local dashboard API to same-origin and loopback (b3974e6)
Bug Fixes
- add-entry: delegate flag validation to shared validateFlags (3507239)
- agent-inbox: seed the queue under the lock, not before it (e585853)
- ashby: stop retrying a permanent failure, and honour a clamped Retry-After (#3072) (27fcd48)
- ashby: surface remote work model in the location string (878e068)
- batch: keep JD word count machine-readable under FORCE_COLOR (bf9a6ae)
- classify-tier: Associate + an academic rank is not entry-level (#3178) (ef347fb)
- cli: close the missing-operand hole for value-taking flags (#3087) (201aeca)
- cli: validate browser-extract flags and honour both value forms (cfe50c3)
- cli: validate fix-slugs flags (c4a0cc2)
- cv: honor Korean profile font theme (70a062c)
- dates: seven more today-gates resolve in UTC (2e4458e)
- deps: update web npm dependencies (major) (1207eae)
- detect-reposts: concurrent openings were reported as reposts (18ff33d)
- followup-cadence: validate CLI flags via the shared helper (#3196) (ec800a2)
- greenhouse: populate job.description from the boards API content field (#3175) (f1c1c65)
- liveness: a dead third-party host must not poison the whole verdict (1389e6c)
- liveness: add a LinkedIn rung so LinkedIn postings get a real verdict (#3179) (255bfc9)
- locks: one recovery judgment, imported by all three copies (638fdc4)
- locks: share the waiting half of the protocol with the three lock copies (39f87cd)
- pdf: name both sides when the lexical containment check fires (#3162) (98cc650)
- pdf: name canonicalization failure separately from a real workspace escape (e4a21ba)
- pdf: stop the batch-evaluate fixture leaking its tracker env (#3162) (328fd38)
- pipeline-lock: a vanished lock is not a lock you may delete (680419f)
- pipeline-lock: carry the judged directory's identity to the rm (7ada146)
- plugins: discover a plugin directory that is symlinked into a plugin root (b9fe775)
- portals.example: name the support ROLE, not the whole domain (d57a243)
- providers/lever: fold categories.allLocations into location (e3260d8)
- providers: retire echojobs, feed is gone behind bot protection (2c42733)
- providers: validate resolved addresses before connecting (DNS rebinding guard) (#3096) (d8d4d94)
- rename-sync: migrate 5 vulnerable call sites to renameSyncWithRetry (#3046) (213c281)
- salary-gap: treat a period as thousands grouping, not a decimal point (#3174) (b8e5bcb)
- set-status: resolve --report links from the Notes cell on customized layouts (#3075) (ae70a41)
- templates: extend profile font_family override to ja and zh blocks (5291cc7)
- templates: keep a project's tech line with the description above it (676efcd)
- tests: assert flag echo by substring, not by unescaped RegExp (6c2220f)
- tests: assert the flag echo with includes instead of an unescaped RegExp (743622d)
- tests: guard the web/ mirror import behind existsSync (e09e3cd)
- tests: keep the end of a failing script's output, not just the head (#3035) (a0f4622)
- tests: make the suite symlink-aware for externalized user layers (7d97d14)
- update: refuse non-canonical paths in the local declaration file (764f20f)
- updater: parse the SYSTEM_PATHS array instead of scraping it with a regex (#3099) (61f8850)
- updater: settle same-version SHA mismatch on tree content, not SHAs (b00619d)
- update: stop misreading upstream's own content as a local edit (#3094) (50c5400)
- verify-portals: decode the HTML entities a board page serves in its title (eb20257)
- verify-portals: stop the slug repair path adopting a stranger's board (d3b830d)
- web: give the methodology link a real tap target and a new-tab cue (#3023) (344a116)
- web: keep child stderr out of the status response on the crash path (#3022) (883ebec)
- web: keep the query string in the Explore dedup key so distinct postings don't collapse (#3082) (275e213)
- web: keep the run stream alive during silent agent phases (#3026) (aaeb114)
- web: report the uncapped weekly match count while keeping the render bounded (#2662) (6e9f029)
- web: stamp pipeline first_seen with the local day, not UTC (#3081) (809e93b)