{"id":51440749,"url":"https://github.com/lomartins/job-hunter-skill","last_synced_at":"2026-07-05T11:30:43.671Z","repository":{"id":357699764,"uuid":"1237755508","full_name":"lomartins/job-hunter-skill","owner":"lomartins","description":"Local-first, PII-safe job-hunting copilot. Scrape boards, kanban-track applications, auto-fill ATS forms, tailor resumes per JD — Claude Code skill + CLI + local webapp.","archived":false,"fork":false,"pushed_at":"2026-05-13T22:08:33.000Z","size":1873,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-14T00:36:56.249Z","etag":null,"topics":["ats","automation","claude-code","claude-plugin","claude-skill","fastapi","htmx","job-board","job-search","job-tracker","kanban","pii","playwright","privacy","python","reactive-resume","resume","self-hosted","sqlite","web-scraping"],"latest_commit_sha":null,"homepage":"https://github.com/lomartins/job-hunter-skill","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lomartins.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-13T13:31:43.000Z","updated_at":"2026-05-13T22:08:37.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/lomartins/job-hunter-skill","commit_stats":null,"previous_names":["lomartins/job-hunter-skill"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/lomartins/job-hunter-skill","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lomartins%2Fjob-hunter-skill","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lomartins%2Fjob-hunter-skill/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lomartins%2Fjob-hunter-skill/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lomartins%2Fjob-hunter-skill/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lomartins","download_url":"https://codeload.github.com/lomartins/job-hunter-skill/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lomartins%2Fjob-hunter-skill/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35153107,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-05T02:00:06.290Z","response_time":100,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ats","automation","claude-code","claude-plugin","claude-skill","fastapi","htmx","job-board","job-search","job-tracker","kanban","pii","playwright","privacy","python","reactive-resume","resume","self-hosted","sqlite","web-scraping"],"created_at":"2026-07-05T11:30:42.962Z","updated_at":"2026-07-05T11:30:43.658Z","avatar_url":"https://github.com/lomartins.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# job-hunter\n\n\u003e A self-hosted, PII-safe job-search command center — for Claude Code, Codex, Cursor, and the terminal.\n\n[![CI](https://github.com/lomartins/job-hunter-skill/actions/workflows/ci.yml/badge.svg)](https://github.com/lomartins/job-hunter-skill/actions/workflows/ci.yml)\n[![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)\n[![Plugin Version](https://img.shields.io/badge/dynamic/json?label=version\u0026query=%24.plugins%5B0%5D.version\u0026url=https%3A%2F%2Fraw.githubusercontent.com%2Flomartins%2Fjob-hunter-skill%2Fmain%2F.claude-plugin%2Fmarketplace.json)](.claude-plugin/marketplace.json)\n[![Python 3.12+](https://img.shields.io/badge/python-3.12+-3776ab.svg)](https://www.python.org/)\n[![Claude Code](https://img.shields.io/badge/Claude%20Code-skill-d97757.svg)](https://github.com/anthropics/claude-code)\n\nJob hunting buried under a hundred tabs? **job-hunter** scrapes job boards, tracks every application kanban-style in a local SQLite DB, fills ATS forms in `shadow` or `auto` mode, surfaces salary distributions from your own pipeline, and tailors a [Reactive Resume](https://github.com/amruthpillai/reactive-resume) per JD — all without ever sending your phone, ID, or session cookies to a model.\n\nWorks for **any tech role** — backend, frontend, mobile, data, ML, infra, devrel, security, design-eng. Drop your role keywords in `profile.yaml` once and the same skill works for a senior platform engineer, a junior data analyst, or a staff designer.\n\n## Webapp\n\nLaunched with `job-hunter web` (localhost-only, no auth):\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"50%\"\u003e\n      \u003ca href=\"docs/screenshots/jobs.png\"\u003e\u003cimg src=\"docs/screenshots/jobs.png\" alt=\"Joblist with filter, sort, currency + period selectors\" /\u003e\u003c/a\u003e\n      \u003cp align=\"center\"\u003e\u003cb\u003eJoblist\u003c/b\u003e — filter, sort, currency + period conversion\u003c/p\u003e\n    \u003c/td\u003e\n    \u003ctd width=\"50%\"\u003e\n      \u003ca href=\"docs/screenshots/tracker.png\"\u003e\u003cimg src=\"docs/screenshots/tracker.png\" alt=\"Pipeline tracker kanban with drag-and-drop\" /\u003e\u003c/a\u003e\n      \u003cp align=\"center\"\u003e\u003cb\u003eTracker\u003c/b\u003e — kanban with drag-and-drop, tag filter\u003c/p\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"50%\"\u003e\n      \u003ca href=\"docs/screenshots/detail.png\"\u003e\u003cimg src=\"docs/screenshots/detail.png\" alt=\"Per-job detail page with Claude Code command launcher\" /\u003e\u003c/a\u003e\n      \u003cp align=\"center\"\u003e\u003cb\u003eDetail\u003c/b\u003e — Claude Code commands, stage/notes, edit fields\u003c/p\u003e\n    \u003c/td\u003e\n    \u003ctd width=\"50%\"\u003e\n      \u003ca href=\"docs/screenshots/metrics.png\"\u003e\u003cimg src=\"docs/screenshots/metrics.png\" alt=\"Metrics page with daily/weekly application charts\" /\u003e\u003c/a\u003e\n      \u003cp align=\"center\"\u003e\u003cb\u003eMetrics\u003c/b\u003e — apps per day / week, by stage, by source\u003c/p\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## What you get\n\n- **11 sources out of the box** — LinkedIn, Indeed, Glassdoor, Gupy, RemoteOK, Job na Gringa, Remotive, We Work Remotely, Himalayas, Programathor, Coodesh. New scrapers via a `learn.py` adapter that drafts YAML from any unknown form.\n- **Full pipeline tracking** — `discovered → queued → applying → applied → screening → technical → behavioral → offer / rejected / withdrawn`, with note-bearing transitions, flagging, and structured tags.\n- **Local FastAPI + HTMX webapp** at `127.0.0.1:8765` — kanban tracker with drag-and-drop stage moves, filter by tag/source/stage/flag, sort by match/date/salary, currency conversion (BRL/USD/EUR via free ECB rates), markdown-rendered JDs, daily/weekly application charts.\n- **Match score** per job derived from your profile + JD heuristics (seniority, country lock, on-site mismatch, US-clearance, etc.).\n- **Salary aggregator** — p25/median/p75 from your own scraped data, no live Glassdoor scraping needed.\n- **AI form-fill in two modes** — `shadow` pauses before submit, `auto` requires 5 reliability gates *and* explicit consent.\n- **Resume tailoring** — `/job-hunter:tailor-resume \u003cid\u003e` emits Reactive Resume JSON tuned to the JD.\n- **Claude Code slash commands** — `discover`, `apply`, `dig`, `tailor-resume`, `validate`, `web`, `tracker`, `status`, `review`, `doctor`.\n\n## PII-safe by design\n\nYour personal data (national ID, phone, address, salary expectations, session cookies) lives in `~/.config/job-hunter/secrets/personal.env` — `chmod 600`, and the **model is explicitly forbidden** to read it via Read tool, cat/head/tail/grep, or any pipe whose output enters the conversation. The CLI loads it via `python-dotenv` in a child process; the model only ever sees field schemas. CI enforces this: `lint_secret_leaks.py` blocks any PR that would echo PII into logs, screenshots, or artifacts.\n\n## Install\n\n### Recommended: Claude Code plugin marketplace\n\n```\n/plugin marketplace add lomartins/job-hunter-skill\n/plugin install job-hunter@lomartins-skills\n```\n\n### Manual (Claude Code)\n\n```bash\ngit clone git@github.com:lomartins/job-hunter-skill.git ~/.claude/skills/lomartins-job-hunter-skill\nln -s ~/.claude/skills/lomartins-job-hunter-skill/skills/job-hunter ~/.claude/skills/job-hunter\n```\n\n### Codex CLI / Cursor / Gemini CLI\n\n`job-hunter` follows the open Agent Skills standard. Clone into the host's skill dir:\n\n```bash\ngit clone git@github.com:lomartins/job-hunter-skill.git ~/.codex/skills/job-hunter-skill\n# Cursor:  ~/.cursor/skills/\n# Gemini:  ~/.gemini/skills/\n```\n\n### Install the CLI binary\n\nThe skill ships a Python CLI that does the actual work. Install once:\n\n```bash\nuv tool install --from git+https://github.com/lomartins/job-hunter-skill.git job-hunter\nplaywright install chromium\n```\n\nThis puts `job-hunter` and the shorter alias `job` on your PATH.\n\n## 60-second quickstart\n\n```bash\n# 1. Initialize XDG dirs and copy templates\njob init\n\n# 2. Edit your profile — role keywords drive matching (no PII goes here)\n$EDITOR ~/.config/job-hunter/profile.yaml\n#   roles: [backend engineer, golang, distributed systems]\n#   roles: [senior frontend, react, typescript]\n#   roles: [data engineer, dbt, snowflake]\n#   roles: [staff android, kotlin, kmp]      # whatever fits you\n\n# 3. Add your secrets (kept out of model context)\n$EDITOR ~/.config/job-hunter/secrets/personal.env\nchmod 600 ~/.config/job-hunter/secrets/personal.env\n\n# 4. Discover roles from RemoteOK (no auth needed)\njob discover --source remoteok\n\n# 5. See what landed\ncat ~/.local/share/job-hunter/tracking.md     # human-readable mirror\njob list --stage discovered                    # CLI view\njob web                                        # or: visual triage in a browser\n\n# 6. Queue something and apply in shadow mode\njob queue 7\njob apply 7 --mode shadow\n```\n\nThe webapp listens on `http://127.0.0.1:8765` by default (localhost-only, no auth, no PII exposed). Pass `--port` to override.\n\n## Architecture\n\n```mermaid\nflowchart LR\n    subgraph Sources\n        L[LinkedIn]\n        G[Gupy]\n        R[RemoteOK]\n        J[Job na Gringa]\n        E[7 more...]\n    end\n    subgraph Skill\n        D[(SQLite jobs.db)]\n        MD[tracking.md]\n        AD[Adapters YAML]\n        AP[apply.py]\n        LE[learn.py]\n    end\n    subgraph Forms\n        F1[Gupy form]\n        F2[Greenhouse form]\n        F3[Workday form]\n    end\n    subgraph PII[chmod 600 — never read by model]\n        S[personal.env]\n    end\n\n    L \u0026 G \u0026 R \u0026 J \u0026 E --\u003e|scrape| D\n    D --\u003e MD\n    D --\u003e AP\n    AD --\u003e AP\n    AP --\u003e|fill| F1 \u0026 F2 \u0026 F3\n    AP -.-\u003e|secret.* lookups at runtime| S\n    F1 \u0026 F2 -.unknown form.-\u003e LE\n    LE --\u003e|draft adapter| AD\n```\n\n## Source compatibility\n\n| Source | Phase | Method | Auth | Firecrawl boost? |\n|--------|-------|--------|------|------------------|\n| Job na Gringa | 1 | HTML | — | No |\n| LinkedIn | 1 | HTML + cookie | `LINKEDIN_LI_AT` | No (cookie auth) |\n| Gupy | 1 | HTML | — | No |\n| RemoteOK | 1 | JSON API | — | No |\n| **Indeed** | **0.9** | **HTML, captcha-aware** | **—** | **Yes** |\n| **Glassdoor** | **0.9** | **HTML + cookie or Firecrawl** | **`GLASSDOOR_GD_ID` + `_UAC`** | **Yes** |\n| Remotive | stub | JSON API | — | — |\n| We Work Remotely | stub | RSS | — | — |\n| Himalayas | stub | HTML/GraphQL | — | — |\n| Programathor | stub | HTML | — | — |\n| Coodesh | stub | HTML | Optional | — |\n| Trampos.co | stub | HTML | — | — |\n| Arc.dev | stub | HTML | Required | — |\n\nSet `FIRECRAWL_ENDPOINT=http://localhost:3002` in `personal.env` to route Indeed + Glassdoor through a self-hosted Firecrawl instance (handles JS rendering + anti-bot). Apply-path is hard-disabled when Firecrawl is set. See [`references/firecrawl.md`](skills/job-hunter/references/firecrawl.md).\n\n## Salary distribution from your own pipeline\n\nAfter running discover across a few sources, get the role's salary distribution from the data you've actually seen — no live Glassdoor scraping needed:\n\n```bash\njob-hunter discover --source indeed\njob-hunter discover --source remoteok\njob-hunter salary --role \"backend engineer\" --location \"united states\"\njob-hunter salary --role \"kotlin\"           --location brazil\njob-hunter salary --role \"data engineer\"    --location remote\n```\n\nOutputs p25 / median / p75 per currency + a suggested expectation (p75 + 10% padding). The `--role` matches against title substrings, so use whichever keyword density matches your search.\n\n## Adapter platform support\n\n| Platform | Adapter shipped | Auto-eligible default |\n|----------|-----------------|-----------------------|\n| Gupy | ✓ | ✗ |\n| Greenhouse | ✓ | ✗ |\n| Lever | ✓ | ✗ |\n| Workday | ✓ | ✗ |\n| Ashby | ✓ | ✗ |\n| SmartRecruiters | (learned via `learn.py`) | — |\n| Recruitee | (learned) | — |\n| BambooHR | (learned) | — |\n| Personio | (learned) | — |\n| Jobvite | (learned) | — |\n\nAuto-eligibility flips on per-signature after three consecutive successful shadow submits and an explicit `job adapter mark-auto-eligible \u003csig\u003e`.\n\n## Slash commands (Claude Code plugin install)\n\n| Command | What it does |\n|---------|-------------|\n| `/job-hunter:discover [source]` | Pull new postings (default: `remoteok`). |\n| `/job-hunter:list [filters]` | Pipeline table. |\n| `/job-hunter:track \u003curl\u003e` | Track a specific posting + queue it. |\n| `/job-hunter:apply \u003cid\u003e` | Preview the form-fill plan (dry-run). |\n| `/job-hunter:dig \u003cid\u003e` | Re-fetch JD + brief: fit, friction, tailoring angles, next move. |\n| `/job-hunter:tailor-resume \u003cid\u003e` | Generate a [Reactive Resume](https://github.com/amruthpillai/reactive-resume) JSON tailored to the JD. |\n| `/job-hunter:validate [id]` | Pre-flag obvious non-fits (junior, country-locked, on-site wrong country). |\n| `/job-hunter:web` | Launch the local triage webapp. |\n| `/job-hunter:status` | Pipeline summary + suggested next steps. |\n| `/job-hunter:review` | Paused adapters + inbox drafts. |\n| `/job-hunter:sync` | Regenerate `tracking.md`. |\n| `/job-hunter:doctor` | Validate install / perms / deps. |\n\n## PII isolation\n\nThe model is forbidden to read `~/.config/job-hunter/secrets/personal.env`. It works against `assets/personal.env.example` (empty-value template) for schema, and the CLI loads real values via `python-dotenv` at runtime in a child process. The webapp reads the SQLite DB only — it never opens the secrets file.\n\nCI runs `lint_secret_leaks.py` on every PR; pre-submit checks block any form fill that would echo PII into logs or screenshots. See [`skills/job-hunter/SKILL.md`](skills/job-hunter/SKILL.md#forbidden-actions-pii-isolation) for the full forbidden-action list.\n\n## Contributing\n\nSee [`skills/job-hunter/references/decisions.md`](skills/job-hunter/references/decisions.md) for the phase plan and [`skills/job-hunter/references/`](skills/job-hunter/references/) for area-specific docs. New adapters welcome via `job adapter contribute \u003csignature\u003e`.\n\n## License\n\nApache-2.0. The skill never transmits PII to model servers — see [PII isolation](#pii-isolation) and the [decisions doc](skills/job-hunter/references/decisions.md) for the architectural enforcement.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flomartins%2Fjob-hunter-skill","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flomartins%2Fjob-hunter-skill","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flomartins%2Fjob-hunter-skill/lists"}