{"id":47800495,"url":"https://github.com/suxrobgm/jobpilot","last_synced_at":"2026-06-29T23:00:28.499Z","repository":{"id":346069853,"uuid":"1188412621","full_name":"suxrobGM/jobpilot","owner":"suxrobGM","description":"Claude Code plugin that autonomously searches job boards, auto-fills applications, generates cover letters, and preps for interviews - powered by your resume","archived":false,"fork":false,"pushed_at":"2026-06-29T21:36:48.000Z","size":5279,"stargazers_count":28,"open_issues_count":0,"forks_count":11,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-29T22:21:33.436Z","etag":null,"topics":["automation","claude-code","claude-code-plugin","cover-letter","job-application","job-search","playwright","resume"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/suxrobGM.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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-22T03:17:24.000Z","updated_at":"2026-06-29T21:36:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/suxrobGM/jobpilot","commit_stats":null,"previous_names":["suxrobgm/jobpilot"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/suxrobGM/jobpilot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suxrobGM%2Fjobpilot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suxrobGM%2Fjobpilot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suxrobGM%2Fjobpilot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suxrobGM%2Fjobpilot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/suxrobGM","download_url":"https://codeload.github.com/suxrobGM/jobpilot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suxrobGM%2Fjobpilot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34945707,"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-06-29T02:00:05.398Z","response_time":58,"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":["automation","claude-code","claude-code-plugin","cover-letter","job-application","job-search","playwright","resume"],"created_at":"2026-04-03T16:59:38.480Z","updated_at":"2026-06-29T23:00:28.400Z","avatar_url":"https://github.com/suxrobGM.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JobPilot\n\nA local-first AI job-application app. An Elysia + PostgreSQL API owns all\nstate, a Next.js web UI talks to it, and an embedded Claude Code or Codex\nterminal session runs the JobPilot provider skills against real job boards via\nPlaywright.\n\n## Components\n\n- **Web app** ([apps/web/](apps/web/)) - `http://localhost:4100`. The Next.js\n  UI for profile, credentials, resumes, job boards, applications, campaigns,\n  and the batch queue. It embeds an xterm.js terminal panel and exposes \"Run\n  autopilot\" / \"Run apply\" buttons that inject slash commands.\n- **API** ([apps/api/](apps/api/)) - `http://localhost:4101`. Bun + Elysia +\n  Prisma backend that owns all persistence (PostgreSQL; resumes under\n  `apps/api/storage/`) and serves the typed `/api/*` surface (Swagger at\n  `/swagger`).\n- **JobPilot.Terminal** ([apps/terminal/](apps/terminal/)) -\n  `http://localhost:4102`. .NET 10 ASP.NET Core process that owns one active\n  provider PTY (ConPTY) and bridges it to the web UI over WebSocket. The\n  terminal drawer can switch between Claude Code and Codex.\n- **Plugin** ([plugin/](plugin/)) - one provider-neutral plugin loaded by both\n  providers, with no generation step. It holds the hand-authored skill pack\n  (`plugin/skills/\u003cname\u003e/SKILL.md` plus shared setup, auth, browser-tips, and\n  form-filling docs under `plugin/skills/shared/`), the Playwright MCP config\n  (`plugin/.mcp.json`), and a manifest per provider\n  (`plugin/.claude-plugin/plugin.json`, `plugin/.codex-plugin/plugin.json` -\n  both name the plugin `jobpilot`).\n  - **Worker subagents** ([plugin/agents/](plugin/agents/)) - `job-worker`\n    (per-job score/apply) and `outreach-worker` (contact discovery + compose)\n    run the heavy browser/web work in an isolated context so long campaigns\n    don't fill the main conversation and trigger compaction. Claude\n    auto-discovers them from `plugin/agents/`; Codex definitions live at\n    [.codex/agents/](.codex/agents/) (repo root) and point back at the same\n    `plugin/agents/*.md` procedures. Any runtime that can't load custom\n    subagents simply runs those procedures inline - same behavior, no isolation\n    (see `plugin/skills/shared/setup.md` → \"Worker subagents\").\n  - Claude: `claude --plugin-dir plugin`.\n  - Codex: auto-discovered via\n    [.agents/plugins/marketplace.json](.agents/plugins/marketplace.json)\n    (`source.path: ./plugin`) when launched at the repo root\n    (`codex --no-alt-screen -C .`). Enable it once from Codex's `/plugin` menu.\n    For Codex subagent isolation outside the repo, copy\n    [.codex/agents/](.codex/agents/) into `~/.codex/agents/`.\n\n## Quick Start\n\n```bash\ngit clone https://github.com/suxrobgm/jobpilot.git\ncd jobpilot\nbun install\nbun run db:up    # starts the local PostgreSQL container (Docker)\nbun run db:setup # generates the Prisma client, runs migrations, seeds default data\nbun run dev      # web :4100 + api :4101 + terminal :4102\n```\n\nOpen `http://localhost:4100` and toggle the Terminal panel.\n\n### Remote database (SSH tunnel)\n\nTo point the API at a remote PostgreSQL, open an SSH tunnel and target it\nlocally. Set the `SSH_TUNNEL_*` / `REMOTE_DB_*` / `LOCAL_DB_PORT` vars in\n[apps/api/.env](apps/api/.env) (see [apps/api/.env.example](apps/api/.env.example)),\nthen:\n\n```bash\nbun run db:tunnel   # binds localhost:5433 -\u003e remote db through the SSH host; Ctrl+C to close\n```\n\nWith the tunnel up, set `DATABASE_URL=postgresql://\u003cuser\u003e:\u003cpass\u003e@localhost:5433/\u003cdb\u003e`\nin [apps/api/.env](apps/api/.env). `db:setup`, `db:studio`, and the API all then\nrun against the remote DB. Set `REMOTE_DB_HOST` to `127.0.0.1` when the database\nruns on the SSH server itself, or to its private host when tunneling via a bastion.\n\n## Skills\n\nSkill workflows live under [plugin/skills/](plugin/skills/) as `\u003cname\u003e/SKILL.md`\ndirectories, edited directly as the single source of truth for both providers.\nShared docs (setup, auth, browser-tips, form-filling) live under\n[plugin/skills/shared/](plugin/skills/shared/). There is no build step.\n\nClaude commands use `/jobpilot:\u003cskill\u003e`, for example:\n\n```text\n/jobpilot:auto-apply senior typescript remote\n```\n\nCodex commands use `$\u003cskill\u003e`, for example:\n\n```text\n$auto-apply senior typescript remote\n```\n\n| Skill             | Purpose                                                              |\n| ----------------- | -------------------------------------------------------------------- |\n| `apply`           | Apply to a single URL (with fit review) or drain the `/queue` page.  |\n| `autopilot`       | Search enabled boards, score, batch-approve, and apply autonomously. |\n| `search`          | Search boards and rank results without applying.                     |\n| `cover-letter`    | Draft a tailored cover letter and run it through the humanizer.      |\n| `upwork-proposal` | Draft a tailored Upwork proposal.                                    |\n| `interview`       | Prepare behavioral, technical, and company-research interview notes. |\n| `scan-inbox`      | Classify new mail, fuzzy-match to applications, propose stage moves. |\n| `get-code`        | Pull the latest verification code or magic link for a board domain.  |\n\n## Email Integration (Gmail)\n\nJobPilot reads your Gmail inbox (to track recruiter replies and auto-fill\nverification codes during login) and sends outreach emails and replies on\nyour behalf. Each user connects Gmail with **their own** Google OAuth client -\nJobPilot ships no shared client, so the app itself needs no Google verification\nor CASA security audit. Setup (once per user):\n\n1. In [Google Cloud Console](https://console.cloud.google.com/apis/credentials),\n   create a new project, then an OAuth 2.0 Client ID (type: **Web application**).\n2. Enable the **Gmail API** for the project under \"APIs \u0026 Services\".\n3. In JobPilot, open **Settings → Email** and copy the **redirect URI** shown\n   there; add it as an authorized redirect URI on your OAuth client (defaults to\n   `http://localhost:4101/api/email/oauth/callback` in dev; in production it's\n   your deployment's API callback URL).\n4. Add the **`gmail.readonly`** and **`gmail.send`** scopes to the consent\n   screen. Google reorganized this UI - it now lives at\n   [Google Auth Platform → Data access](https://console.cloud.google.com/auth/scopes)\n   Click **Add or remove scopes**, search for `gmail.readonly` and\n   `gmail.send`, tick both Gmail API rows, then **Save**. `readonly` lets\n   JobPilot track replies and read verification codes; `send` lets it send\n   outreach emails and replies. Without `readonly` the Gmail API returns 403\n   \"insufficient scopes\"; without `send` the mailbox connects read-only and\n   outreach can't send.\n5. Keep **your** app in Testing mode and add your Gmail address under\n   [Audience → Test users](https://console.cloud.google.com/auth/audience).\n   Because it's your own project with you as the sole test user, no\n   verification/CASA is required. Note: Testing-mode refresh tokens expire\n   after ~7 days, so you'll reconnect periodically - publish your own app\n   (still no verification under Google's 100-user test limit) to avoid that.\n6. Back in **Settings → Email**, paste your **Client ID** and **Client\n   secret**, **Save**, then **Connect Gmail**.\n\nThe scopes are `gmail.readonly` and `gmail.send` - JobPilot reads your mail and\nsends outreach emails and replies on your behalf, but never deletes mail. Your\nOAuth client id/secret are stored encrypted per-user (the secret never leaves\nthe server); the connected account is one row per profile in `EmailAccount`.\n\n**Troubleshooting**\n\n- **\"Access blocked: app has not completed the Google verification\n  process\"** - your Gmail isn't on the Test users list. Add it under\n  **Audience → Test users**.\n- **`403 PERMISSION_DENIED - Request had insufficient authentication\nscopes`** - a required Gmail scope (`gmail.readonly` or `gmail.send`) isn't\n  on the consent screen. Add both under **Data access**, then **Disconnect**\n  and reconnect in `/settings` → **Email** so a new token with the right\n  scopes is issued.\n- **Mailbox connects read-only / outreach can't send** - the token was issued\n  without `gmail.send`. Add the `gmail.send` scope under **Data access**, then\n  use **Reconnect to enable sending** in `/settings` → **Email**.\n- **Google 500 after publishing** - you published an app that uses a\n  Sensitive scope. Go back to Testing mode under\n  **Audience → Publishing status → Back to testing**.\n\n## Documentation\n\n- [docs/architecture.md](docs/architecture.md) - architecture walk-through.\n- [docs/self-hosting.md](docs/self-hosting.md) - operations and configuration.\n- [CLAUDE.md](CLAUDE.md) - contributor and agent context.\n\n## Tech Stack\n\n| Layer              | Choice                                         |\n| ------------------ | ---------------------------------------------- |\n| Runtime            | Bun 1.3                                        |\n| Framework          | Next.js 16 (App Router, RSC, typed routes)     |\n| UI                 | MUI 9 + MUI X DataGrid                         |\n| Forms              | TanStack Form 1 + Zod v4                       |\n| Server state       | TanStack Query 5                               |\n| Database           | PostgreSQL via Prisma 7 + `@prisma/adapter-pg` |\n| Terminal host      | .NET 10 ASP.NET Core, ConPTY via Quick.PtyNet  |\n| Browser automation | Playwright via the Playwright MCP server       |\n\n## License\n\nMIT. The shared humanizer skill is based on the bundled upstream humanizer\npackage under [plugin/skills/humanizer/](plugin/skills/humanizer/), which\nships with its own LICENSE file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuxrobgm%2Fjobpilot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsuxrobgm%2Fjobpilot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuxrobgm%2Fjobpilot/lists"}