v0.9.5 — Application mode (per-posting referrals, profile-driven)
The Application-mode release: a second input front door. Where Campaign mode targets a company, Application mode reads a scored job feed and finds referral candidates for a specific posting — the role's team, hiring manager, recruiter, and warm personas — linked to a job_id the consumer polls for "referral yet?". Runs end to end on host tokens, and the whole agent is now profile-driven, not person-driven.
Highlights (epic #57, P1–P4)
- P1 (#58) —
applications+application_contactstables (migration 009),Applicationmodel, feed parser with drop/error reporting. - P2 (#59) —
/network-jobs: parse feed → per posting persist → role-biased discovery (--keywords) → classify (host subagent) → ingest → link tojob_id, with cross-mode dedup via canonical LinkedIn URL. - P3 (#60) — role-aware drafting (drafts name the specific role via
--job-id), per-job_idreferral status rollup (/network-jobs --status), ask-rotation scoped by posting. - P4 (#61) — profile-driven generalization: new
src/core/profile.py+~/.networking-agent/profile.yaml(feedprofile_refselectsprofiles/<ref>.yaml;NETWORKING_AGENT_PROFILEactivates a named profile pipeline-wide). The ~8 hardcoded aerospace/UIUC spots moved into the default profile — byte-identical zero regression for existing installs. Free-formfunction/target_keywordsresolve against the profile taxonomy to wire the ranker'starget_focus(+10 team match). A backend SWE, a nurse, or a finance analyst use the same feed schema — only the profile differs. Closes ROADMAP B1 + B2.
Hardening (post-merge review, PRs #72–#73)
Named-profile activation end to end, clean ProfileError on malformed profile.yaml, explicit empty lists honored (no fabricated employer hooks), mtime-cached profile loading, one shared focus-label validator, plain-string focus labels pipeline-wide, ingest-boundary label validation.
Quality: 1255 tests, 98.94% line+branch coverage (gate 98), ruff clean. Full details in CHANGELOG.md.
🤖 Generated with Claude Code