v1.7.0

Friedrich-M/UniMatev1.7.0Aug 29, 2026by MadsLorentzen

Upgrading?

Key Highlights

  • Public API for flows, triggers, and AI agents
  • Google event templates for appointments
  • Automatic customer scan from channel history
  • Multi-page broadcast support with per-page templates

New Features

  • Public API for automation and appointments
  • Google event templates
  • Auto customer scan
  • Multi-page broadcasts
  • Analytics-scoped public API

Full Release Notes

Two themes this release: **your job search stays yours**, and **stored state tells the truth about what it holds**. The headline fix closes a real privacy leak reported and fixed by the community within a day, and stored jobs now know when their posting has died.

## Highlights

### Fork clones no longer file your private tracker on the upstream repo (#389, #392)
`gh repo fork --clone` - the exact command SETUP.md recommended - sets the **upstream** repo as gh's default, and gh uses the default for *creating issues*. So when your own automation ran `gh issue create` from inside your personalized fork ("file a tracking issue per application" is a natural ask), your application pipeline - target companies, fit scores, personal constraints - was published on a stranger's repo, under your identity, where you can't delete it. Four live instances from two users in one week. SETUP.md now puts `gh repo set-default <you>/ai-job-search` directly in the fork commands with a warning at the point of decision, and a new issue template carries the same heads-up the PR template always had. Reported, diagnosed from primary sources, and fixed by @ayobamiseun. **If your clone predates this release, the fix does not reach you automatically - see "Updating a personalized fork" below.**

### Stored jobs now know when the posting has died (#280, #383)
`linkedin-search detail` gains an `isActive` field: `false` when the posting page renders LinkedIn's own "No longer accepting applications" banner. Detection is scoped to the top card and pinned by fixture tests in both directions - including the false-positive case where recruiter boilerplate quotes the closed phrase inside a *description* (the unscoped first version flagged it; the shipped version provably does not). `/scrape` records closed-at-source jobs as `"status": "expired"` - marked, never silently dropped - which addresses the ghost-LinkedIn-jobs class (#331): an expired LinkedIn URL redirects to a *similar live job*, so a stored hit could die unnoticed between scrape and click. Diagnosed and first implemented by @navakanth1984, adopted and finished by @ayobamiseun with the original commit preserved.

### Fractional flags stop silently changing your search (#373)
`freehire-search --jobage 0.5` ("last half day") truncated to `0`, which disabled the freshness filter entirely - exit 0, no error, stale postings presented as fresh, on a default-ON `/scrape` portal. Numeric flags now accept whole numbers of at least 1 and reject everything else with the standard `BAD_ARG` error, matching the Danish CLIs' validation. Reported with a stubbed-network repro and fixed by @ayobamiseun. (The `linkedin-search` sibling, #371, is reserved by its reporter and lands separately.)

### The ATS text check works on Windows without Poppler (#369)
`/apply`'s mechanical parseability check and `tools/verify_pdf.py` now extract the CV text layer with **pypdf** first (BSD-licensed, one `pip install`), falling back to Poppler's `pdftotext`, and degrading to a visual review only when both are missing - so the check that catches invisible-to-ATS CVs actually runs on a stock Windows machine. Includes the UTF-8 subprocess-decoding fix that kept Danish characters intact on the fallback path. Contributed by @sdrarunvarshan.

### `/reset profile` now actually clears your profile (#364)
Two of the six files `/setup` personalizes were left out of the wipe: `04-job-evaluation.md` (your match areas, career goals, financial constraints) was explicitly labelled "framework rules, not candidate data" while holding both, and `job-scraper/search-queries.md` (your boards, titles, city, commute tiers) appeared nowhere in the reset at all. Both are now previewed and cleared, and a CI guard derives the reset list from `/setup`'s own targets so a future forgotten file fails loudly. Reported via his own issue and fixed by @pchukwuemeka424.

## Also in this release

- **CI tests the full documented Python range** (#370) - a 3.10-3.14 matrix replaces the 3.12 pin; grew out of an independent cross-platform verification by @atiqur-rahman-pro.
- **Company research is cached between `/apply` and `/interview`** - a 30-day `company_research/` cache (gitignored, guarded) stops the same company being researched twice from scratch; verification-before-claims is unchanged, only discovery is cached.
- **CI compiles the LaTeX examples on Debian bookworm's apt TeX Live** as a second leg, so the moderncv 2.3.1 compile fix is guarded in the environment that actually had the bug.
- **`salary_lookup.py` normalizes dotted legal suffixes** (#356) - "A.M.B.A." and "amba" now match identically. Thanks @Ritik650.

## Updating a personalized fork

Versioned files touched since v1.6.0:

| File | v1.6.0 | v1.7.0 |
|---|---|---|
| `04-job-evaluation.md` | 1.2.4 | 1.2.6 |
| `05-cv-templates.md` | 1.4.2 | 1.4.3 |

Run `python3 tools/check_upstream_updates.py` for per-file diffs.

Four things to check after pulling:

1. **Run this today in every existing clone, before anything else:**
   ```
   gh repo set-default <your-username>/ai-job-search
   ```
   The SETUP.md fix only reaches clones made *after* this release. If your clone came from `gh repo fork --clone`, gh is pointing `issue create` (and more) at the upstream repo right now. Check with `gh repo set-default --view`.
2. **Scripts passing fractional values to `freehire-search` numeric flags now get exit 1** (`BAD_ARG`) instead of a silently altered query. `--jobage 0` is also rejected - it was an undocumented "no filter" alias.
3. **`seen_jobs.json` may gain `"status": "expired"` entries** from `/scrape` runs. No migration needed - it is existing status vocabulary, and expired jobs are marked, never deleted.
4. **`/reset profile` now clears `04-job-evaluation.md` and `search-queries.md` too.** If you relied on the old (buggy) behavior preserving those two, export them before your next reset.

Related Repositories