Skip to content

Releases: nazboyko/applypack

v1.0.0 — first stable release

Choose a tag to compare

@nazboyko nazboyko released this 01 Sep 01:56
1171bc1

What's new

  • The whole arc ships: find (22 sources, checked hourly) → verify (ghost-job checklist with evidence URLs) → tailor (deterministic resume scoring + the targeted editor) → apply (fact-gated cover letters, PDF/DOCX) → track (kanban + stale-application nudges).
  • applypack.dev is live, with a browser demo of the real scoring module at /demo/ — edit the resume and watch the score recompute; adding a word the AI marked cannot-claim moves nothing.
  • 5 swappable AI backends with auto-failover (Claude Code / Gemini / Codex CLIs, Anthropic API, any OpenAI-compatible endpoint incl. free local models); your data stays in your own Postgres.

Schema

  • no schema changes since v0.11.1

Verification

  • 741 tests green; production site + demo exercised in a real browser

References

  • PR #40 (landing) · PR #41 (demo) · PR #42 (bump)

v0.11.1 — rename + launch hygiene

Choose a tag to compare

@nazboyko nazboyko released this 01 Sep 00:40
d701ae9

What's new

  • Renamed to ApplyPack (repo nazboyko/applypack, old URLs redirect). Postgres role/db/volume keep their jobhunter names — existing deployments need no migration; if you rename your local checkout folder, copy the Docker volume first.
  • SECURITY.md (private vulnerability reporting is enabled) + CODE_OF_CONDUCT.md; CONTRIBUTING states the MIT in-bound license.
  • README: 22 sources (not 16), cover-letter row, fresh screenshots under the new brand (synthetic demo data).
  • User-Agent now reports the real version, derived from package.json (guard-tested).

Schema

  • no schema changes

Verification

  • 739 tests green; dashboard rebuilt, all 9 routes 200, brand verified at 1200px and 375px, 0 console errors

References

  • PR #37 (rename) · PR #38 (hygiene)

v0.11.0 — apply-link flags

Choose a tag to compare

@nazboyko nazboyko released this 31 Aug 22:03

What's new

  • Four apply-link flags join Job.redFlags at ingest: apply-url-missing, apply-url-unusable, apply-url-shortened, apply-url-not-an-application — visible on /jobs/:id and in Telegram alerts with no new UI.
  • backfill-apply-link-flags annotates already-stored rows without an AI call (additive, idempotent, --dry-run reads only).
  • The planned trust score (F13) was dropped after measuring its four penalties on all 814 stored jobs — three would have been wrong for our data (185 non-https rows are one host's stale Greenhouse config; every missing-URL row is a hand-pasted MANUAL job; the domain-mismatch check flags only synthetic aggregator rows).

Schema

  • no schema changes

Verification

  • 738 unit tests green; flags merged at all three persist paths; backfill dry-run measured against the full corpus

References

  • ADR 0023 (apply-link flags, not a trust score) · plan §14 (F13) · PR #36

v0.10.0 — safe local defaults

Choose a tag to compare

@nazboyko nazboyko released this 31 Aug 19:44

What's new

  • The dashboard no longer binds to every network by default. Running the project without Docker used to put an unauthenticated dashboard — jobs, resume text, cover letters, settings, the Telegram token form — on whatever network the machine was joined to. It now listens on loopback unless you say otherwise; Docker installs are unchanged, since compose already published the port on localhost only.
  • A fresh install starts without an AI key. Copying .env.example and running anything used to fail with ANTHROPIC_API_KEY: required, including the dashboard where that key is configured. The dashboard now starts with no credential at all and the AI engine tab tells you which engines are usable.
  • The "Running without Docker" README section was verified step by step on a clean clone and now says what it actually takes: DATABASE_URL is the only value you must set, and both commands run from the repository root.
  • package.json and CHANGELOG.md were re-synced with the tag history (both had stopped at 0.2.1 while tags ran to v0.9.0).

Schema

  • No schema changes.

Verification

  • lint:types + npm test green — 688 tests, +5 covering the config schema.
  • Clean-clone install re-run with the fixes: the dashboard boots from .env.example verbatim with no API key, logs host: "127.0.0.1", answers 200 on loopback, and the LAN address is refused. 36 migrations applied to an empty database, 39 seed upserts, all dashboard routes and /static/*.mjs 200.
  • docker compose config confirms the web service still resolves WEB_HOST: 0.0.0.0.

References

  • PR #34
  • ADR 0013 / 0014 (engine chain resolves at runtime, so a boot-time credential check was redundant)

v0.9.0 — untrusted-content fences

Choose a tag to compare

@nazboyko nazboyko released this 31 Aug 19:29
9a92f27

What's new

  • Job descriptions, resumes and pasted pages are wrapped in an explicit fence before any model sees them, with one shared directive stating the text inside is data, never instructions.
  • The classifier — which every fetched job passes through and which had no protection at all — is covered, along with the resume, match, cover-letter, verification and paste-extraction prompts.
  • An injection attempt is no longer silently ignored: it is recorded as a prompt-injection-attempt red flag on the job, so the attempt itself becomes visible.
  • Verification, the only path with web search, additionally refuses to fetch a URL the posting nominates or to treat such a page as corroboration.
  • A CI guard derives its roster from the code itself, so a prompt builder or an AI call site added later cannot skip the fence.
  • Fixed a latent bug where posting text starting with a dash could be read as a command-line flag by the local Claude CLI, and tightened the liveness checker to re-verify a URL after redirects.

Schema

  • No schema changes. The attempt is recorded through the red_flags array that already existed.

Verification

  • 683 tests green; the guard was shown to fail on a removed fence, an unregistered builder and a new AI call site; bench:resume 21/21 before and after; classifier scores stayed inside a measured noise band; one real cover letter generated with the fact gate passing.

References

v0.8.0 — cover letters + fact gate

Choose a tag to compare

@nazboyko nazboyko released this 31 Aug 17:27

What's new

  • Cover letters. A "Cover letter" card on every job page drafts a short (120–180 word) letter from your resume, your confirmed facts and the posting — plus the resume match and researched company facts when they exist. Tone select, angle fields that are remembered between letters, in-place editing that autosaves, Regenerate, and "Save as PDF" / "Save as DOCX".
  • A Cover letter page in the menu (/letter): pick a job from a searchable list of your newest matching jobs, or bring a new posting by URL or pasted text. Writing a letter takes about 25 seconds — the fit score is not computed on this path, and the resume match and company research are opt-in.
  • Fact gate (F7). Shipped untagged with PR #31 and surfaced here: every generated letter is checked deterministically against your resume and confirmed facts before you see it. An invented number, employer, title or denied tool triggers one regeneration with the violations quoted; a second failure discards the letter, so nothing unverified is ever stored. Your own edits are flagged, never blocked.
  • Per-engine Cover letter model on Settings → AI engine (an empty slot follows the resume model). All model pickers now save the moment you change them.
  • Letters are written in plain English for a non-technical first reader and normalized to keyboard punctuation — no em dashes, curly quotes or bullets ever reach a stored letter.

Schema

  • CoverLetter table (20260831180000_add_cover_letter).
  • AppSettings.coverAngles (20260831190000_add_cover_angles).

Verification

648 unit tests; 15+ real generations across five engine/model pairs, three input paths and three tones; live chain failover with the · fallback marker; SSRF guard on the URL fetch; 1200/375 screenshots, 0 console errors.

References

ADR 0020 (fact gate), ADR 0021 (letters generate from stored inputs only), docs/feature-expansion-plan.md §8–9, PRs #31 and #32.

v0.7.0 — source health monitoring

Choose a tag to compare

@nazboyko nazboyko released this 31 Aug 05:03
e27af2b

What's new

  • Tracked boards now report whether they are actually answering. Every fetch records a per-source status: ok, empty, slug not found, gated, rate-limited, vendor error, unreachable, unreadable payload.
  • A "Quiet sources" card at the top of /companies lists boards that failed three ticks in a row (Failing) or stayed reachable but returned no posting for 14 days (Silent), each with one-click Re-probe to repair — a clean probe clears the streak.
  • A health dot on every company row, read from the board's raw output rather than from stored jobs, so a strict profile filter never looks like a broken board.
  • Optional line in the daily Telegram digest naming sources that went quiet (/settings → Notifications → "Source health alerts", default on).
  • Turning this on immediately surfaced two boards in this deployment that had been failing silently: GREENHOUSE:pleo (moved to Ashby) and LEVER:plaid.

Schema

  • 20260831170000_add_source_health — additive: Company.lastFetchStatus, Company.consecutiveFailures, Company.lastOkAt, AppSettings.sourceHealthAlerts.

Verification

563 tests pass, tsc --noEmit clean; migration applied in-container; smoke ran a planted bad slug through three ticks (streak 1→2→3, threshold warning fired, row restored); every route 200, screenshots at 1200px and 375px, 0 console errors. npm run test:telegram skipped — escaping covered by unit tests.

References

v0.6.0 — cross-source dedup

Choose a tag to compare

@nazboyko nazboyko released this 31 Aug 03:47
d4b09b4

What's new

  • The same job arriving from two sources is now spotted by a content fingerprint (SimHash over the description) and flagged: "Also listed elsewhere — apply through one channel only" on the job page, in both directions, and as a line in the Telegram alert
  • Nothing is merged or hidden — both rows stay and both are still classified, so a wrong flag costs a note and nothing else
  • backfill-fingerprints.js fingerprints existing jobs and links what it finds; re-running it links nothing new
  • Feed rows that nothing identifies are skipped instead of sharing one synthesised id, and tracking parameters (utm_*, gh_src, fbclid, …) no longer change a job's id — functional ones like gh_jid are kept

Measured, not assumed

The plan's constants were re-measured against the 731 stored jobs first, and two were wrong for this corpus:

  • guard raised to 400 normalized characters — at 200, Jobicy's truncated teasers made two different roles at one company hash identically
  • threshold raised to Hamming 7 — every cross-company match up to 7 was genuine, the first false positive lands at 10
  • the plan's "skip same-company matches" was dropped: 27% of them are genuinely different roles sharing a company's boilerplate

Backfill on the existing corpus linked 6 real cross-listings, including Lemon.io across three aggregators and Reddit on both WeWorkRemotely and its own Greenhouse board.

Schema

  • Job.descriptionSimhash (BIGINT, nullable), Job.crossListedOfJobId (nullable self-FK, ON DELETE SET NULL), index on (fetchedAt, descriptionSimhash) — additive

Verification

  • 524 unit tests green; migration applied through the container init path; backfill dry-run → real run → idempotent re-run; one live fetch tick; screenshots 1200/375, 0 console errors

References

  • ADR 0018 — cross-listing is annotated, never merged
  • docs/feature-expansion-plan.md §4 (F3) · PR #29

v0.5.0 — company starter packs

Choose a tag to compare

@nazboyko nazboyko released this 31 Aug 03:02
70b1969

What's new

  • /companies → "Add a starter pack": curated segments of companies, each board re-probed live before anything is written
  • 86 companies across 5 segments (PHP/Laravel & CMS, JS infra & dev tools, JS/TS product & headless CMS, remote-first, UA-friendly remote)
  • Preview before insert: new boards, boards already tracked, and unresolved names with a reason — a name is never dropped silently
  • Companies land disabled, with an "Enable all" button after the import; re-importing a pack adds nothing
  • ATS probe failures now say what actually happened — rate limiting and vendor outages no longer report "token likely invalid"

Schema

  • no schema changes

Verification

  • 500 unit tests green; live probe smoke on the PHP (23) and UA (11) segments; full UI round-trip in Docker incl. re-import and rejected picks; screenshots 1200/375, 0 console errors

References

  • ADR 0017 — starter-pack entries pin a hand-verified board
  • docs/feature-expansion-plan.md §15 (F14) · PR #28

v0.4.0 — fetchers wave 1

Choose a tag to compare

@nazboyko nazboyko released this 31 Aug 02:07
0e93af5

6 new sources: Recruitee, Breezy, BambooHR, Pinpoint, Rippling + 4 Day Week (robots-allowed /api/v2). JustJoin/NoFluffJobs/NoDesk rejected on robots grounds (ADR 0005 addendum). 6 enum migrations; 480 tests, full-tick smoke 848→27 classified, 0 zod errors.