# Job Sourcing

> Use when the user wants to find open roles. Trigger phrases: "find me jobs", "source roles", "what's open at my target companies", "check for new postings". Reads profile/target-roles.md and target-companies.md, searches company career pages and ATS boards plus aggregators via web search, dedupes, runs a scam/legitimacy screen, and appends new roles to pipeline/tracker.csv as status=found with stable ids. Never auto-applies.

- Skill: `guerrilla2799/job-sourcing` (Agent Skill)
- Install (CLI): `npx skillmds@latest add guerrilla2799/job-sourcing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/guerrilla2799/job-sourcing/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: guerrilla2799 (https://skillmd.com/u/guerrilla2799)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/guerrilla2799/job-sourcing

---


# Job Sourcing

Find, aggregate, dedupe, and legitimacy-check open roles against the user's targets. Turns "what's out there" into clean tracker rows ready for scoring, without ever submitting anything.

## When to use
- "Find me jobs", "source roles this week", "any new postings at my Tier A companies?"
- Recurring sweep, run on a cadence to catch fresh postings (ATS pages update daily)
- After `job-search-setup` defines targets, or after the user adds a company/title

## Inputs
- Reads: `workspace/profile/target-roles.md` (titles + variants, location, comp floor, deal-breakers), `workspace/profile/target-companies.md` (named accounts + company-ICP), `workspace/pipeline/tracker.csv` (to dedupe against and find the next free id)
- Needs from user: nothing required if profile/ exists. Optionally: a max number of roles to add, a recency window (e.g. "posted in last 14 days"), or a specific company/title to focus on. If `profile/` is empty, stop and route to `job-search-setup`.

## Workflow
1. **Load targets.** Pull title variants, location and remote rules, comp floor, and deal-breakers from `target-roles.md`. Pull the named A/B/C list and the company-ICP rubric from `target-companies.md`.
2. **Search, preferring the source of truth.** For each target, run web searches in this priority order (higher = fresher and real, not a stale aggregator repost):
   1. **Company career pages.** `site:<company>.com careers`, or the company's jobs URL directly.
   2. **ATS boards.** These host the real reqs. Search patterns:
      - Greenhouse: `site:boards.greenhouse.io <company>` or `boards.greenhouse.io/<company>`
      - Lever: `site:jobs.lever.co <company>`
      - Ashby: `site:jobs.ashbyhq.com <company>`
      - Workday: `<company> workday careers` (URLs contain `myworkdayjobs.com`)
   3. **Aggregators.** LinkedIn Jobs, Indeed, Wellfound/Otta. Use them to *discover companies you didn't have listed* and to catch roles not yet indexed elsewhere. Treat their postings as leads to verify against the company/ATS page, not as final truth.
   For discovery beyond the named list, search the company-ICP criteria + title (e.g. "Series B fintech" + "Product Marketing Manager" + "remote") to surface new companies, then add them.
3. **Optional bulk scrape.** For high-volume board sweeps, note the JobSpy integration (`docs/integrations.md`), which scrapes LinkedIn/Indeed/Glassdoor/ZipRecruiter in bulk to CSV. Purely optional. The skill works with web search alone. If used, feed its rows into the same dedupe + legitimacy steps below.
4. **Dedupe.** Collapse duplicates by `company + normalized-role-title + url`. The same req reposted on LinkedIn, Indeed, and the ATS is ONE row. Keep the highest-priority source URL (company/ATS over aggregator). Also dedupe against existing `tracker.csv` rows so you never re-add something already tracked. Normalize titles (strip "Sr.", "(Remote)", location suffixes, req numbers) before comparing.
5. **Legitimacy / scam screen.** Score each surviving role against the red-flag list below. Drop anything that trips a hard flag and annotate soft flags in `notes`.

   **Hard flags (drop it):**
   - Upfront payment, "equipment/onboarding fee", or a request for bank/SSN details to apply
   - Contact is a personal email (gmail/outlook) or "text this number on Telegram/WhatsApp" instead of a company domain or ATS apply flow
   - No verifiable company footprint (no real website, no LinkedIn company page, no funding/press)
   - Comp wildly above market for the title with a near-empty JD ("$65/hr, work from home, no experience")

   **Soft flags (keep, but note):**
   - Vague JD with buzzwords and no concrete responsibilities
   - **Ghost job** signals: reposted every 30 days for months, "evergreen" reqs, no named hiring manager, aggregator-only with no ATS/company link
   - Staffing-agency middleman obscuring the real employer
   - Salary "DOE" with no band in a state that requires disclosure
6. **Assign ids and write rows.** For each new real role, take the next stable id (`J001`, `J002`, and so on, never reused), and append a row to `tracker.csv` with `status=found`, `date_found=<today>`, source, url, comp_range if listed, location. Leave `fit_score`, `priority`, and `next_action` blank. `job-fit-scoring` fills those.
7. **Save the raw JD.** Create `workspace/pipeline/applications/<id>-<company>-<role>.md` from `templates/application-record-template.md`, and paste the full raw job description into the record (so later skills score/tailor against real text, not a memory of it). Slug the filename: lowercase, hyphens, no spaces.
8. **Summarize.** Report to chat: N new roles added (with ids), M duplicates collapsed, K dropped for legitimacy (with the reason), and any new companies discovered worth adding to `target-companies.md`.

## Output
- Writes to:
  - `workspace/pipeline/tracker.csv` – new rows, `status=found`, stable ids
  - `workspace/pipeline/applications/<id>-<company>-<role>.md` – one per role, raw JD pasted in
- Format: a chat summary table (`id | company | role | location | comp | source | legitimacy`) plus counts (added / deduped / dropped). Dropped roles are listed with their flag so the user can override if you were wrong.

## Rules & quality bar
- **Never auto-apply and never auto-send.** Sourcing ends at tracked rows. Application is a separate, human-approved step.
- **Company/ATS pages beat aggregators.** When the same role exists on both, keep the ATS/company URL. Aggregator copies go stale and inflate ghost-job noise.
- **Every row is a real, open req.** If you can't confirm the posting is live and the company is real, it doesn't get a row. It gets dropped with a reason.
- **Respect deal-breakers at the source.** If `target-roles.md` says "no on-site only" or "US-remote only", don't add roles that violate it. Note them as dropped rather than adding known-bad rows for `job-fit-scoring` to disqualify later. (Borderline cases: add and let scoring flag.)
- **Stable ids, never reused.** Even if a role is later rejected/withdrawn, its id is retired, not recycled.
- **Don't fabricate comp or dates.** If comp isn't listed, leave `comp_range` blank. Do not estimate into the cell (an ICP-based estimate belongs in `notes`, clearly marked).

## Related skills
- Reads from: `job-search-setup` (targets), and appends alongside `application-tracker`'s schema.
- Hands off to: `job-fit-scoring` (score and prioritize the new `found` rows). Run it immediately after a sourcing sweep. New companies discovered here feed back into `job-search-setup` / `company-research`.

