An end-to-end job-search workstation. Fetch roles, triage them, tailor a custom resume and cover letter for each JD, auto-fill any ATS form, and export production-grade PDFs — without copy-paste.
Live Demo · Codex Batch Protocol · Domain Context · Report a bug
Most job-search tools stop at listing or tracking. Joblit closes the loop:
| Stage | What Joblit does | How |
|---|---|---|
| Discover | Batch-fetch roles from job boards | GitHub Actions workers — Seek + LinkedIn (JobSpy), feature-flagged and extensible |
| Triage | Fast scan, filter, status-track | Two-pane workspace with search and JD rendering |
| Tailor | Generate targeted resume and cover letter | AI prompt engine with versioned rule templates |
| Apply | Auto-fill any ATS application form | Chrome extension with self-learning knowledge base |
| Export | Production-grade PDF output | LaTeX compile pipeline, EN + CN templates |
The product differentiator is the Chrome extension: every correction you make trains a personal knowledge base, so subsequent fills get faster and more accurate.
Joblit is free and open to everyone. Sign in with Google or GitHub; no invitation, manual approval, subscription, or credit card is required.
- Features
- Chrome Extension
- Architecture
- Project Structure
- Quick Start
- Scripts
- Environment Variables
- Codex Batch Workflow
- Testing
- Deployment
- Troubleshooting
- Contributing
- Security
- Acknowledgments
- License
FetchRuntasks with configurable role categories, markets, and filters- Dispatched to GitHub Actions workers — a Seek fetcher (
tools/fetcher/run_seek.py) and the JobSpy fetcher (LinkedIn + more); each source is feature-flagged (e.g.SEEK_FETCH_ENABLED) and stops on any anti-bot challenge by design - Import path with dedupe on
userId + jobUrland tombstone filtering for permanently dismissed URLs - Title/description exclusion rules, work-type / classification filters, and an on-demand full-JD enrich for teaser-only Seek listings at tailoring time
- Two-pane review UI: fast scan on the left, full JD with markdown rendering on the right
- Search, filter, pagination, and status transitions (
NEW/APPLIED/REJECTED) - Batch operations and tombstone tracking on delete
- Multi-step master-resume editor: basics, summary, experience, projects, education, skills
- Bullet-level edits with markdown emphasis and live preview
- Per-locale profiles (
en-AU/zh-CN) with localized LaTeX templates
- Versioned
PromptRuleTemplatewith skill-pack delivery - Prompt generation for resume and cover-letter targets
- Strict schema validation,
promptMetaconsistency checks, evidence-grounded bullets - Manual JSON import path: copy prompt to any external model, import the result back
- LaTeX-based resume and cover-letter rendering with bilingual templates
- Optional persistent storage via Vercel Blob
- Create
NEW-scope batches from filtered jobs - Atomic claim-and-complete loop via
POST /api/application-batches/:id/run-once - Progress tracking via batch summary API
- Full external orchestration protocol documented in AGENTS.md
- Self-service access — anyone can sign in with Google or GitHub OAuth and start using Joblit immediately
- No account gate — there is no invitation, manual approval, subscription, or credit-card requirement
- Internal JobSpy import —
/api/admin/importis a service-to-service route for the fetch worker, protected byIMPORT_SECRET; it is not a user-facing admin console or an account-access mechanism
Manifest V3 extension that auto-fills job application forms using your Joblit resume profile.
Purpose-built field detection per ATS:
| ATS | Adapter | Coverage |
|---|---|---|
| Workday | workday.ts |
Inputs, dropdowns, custom components |
| Greenhouse | greenhouse.ts |
Standard application forms |
| Lever | lever.ts |
Application and referral forms |
| iCIMS | icims.ts |
Career portal forms |
| SuccessFactors | successFactors.ts |
SAP-based application flows |
| Generic | generic.ts |
Fallback for unknown ATS platforms |
Each application teaches the extension:
- Fill — auto-fill detected fields from your resume profile
- Review — floating widget shows what was filled; edit any value inline
- Learn — each correction auto-saves as a mapping rule (field selector → profile path)
- Recall — next time the same field appears, the knowledge base supplies the corrected value
Rule matching priority: user rules → exact form signature → same ATS + domain → same ATS cross-domain. Rules are scoped at three levels (global / ATS-level / site-specific) and managed from the web dashboard.
- Shadow DOM widget — vanilla JS, no framework dependency in content script (~39 KB)
- React-compatible input simulation — dispatches native events to work with React, Angular, and Vue controlled inputs
- Form signature — djb2 hash of field structure for cross-session form matching
- Offline queue — submissions queue locally and sync when back online
- Bilingual UI — English and Chinese via lightweight i18n
Joblit can generate a grounded CV or cover letter through the official Hermes client on the user's own computer. The website sends only a job ID and target to the extension; the extension fetches the canonical Joblit prompt, calls the loopback Hermes Runs API, and returns a strict JSON result to the existing DRAFT editor.
- Uses an unmodified Hermes installation and the user's own
openai-codex/ ChatGPT OAuth session - Binds only to
127.0.0.1; Joblit and Hermes API keys never enter page JavaScript - Disables Hermes memory, MCP, and executable toolsets for the Joblit profile
- Keeps a verified persistent local distribution source so official profile updates remain repeatable
- Reuses an existing
openai-codexlogin and opens OAuth only when Hermes reports logged out - Preserves the existing manual Skill/copy/paste method as fallback
Windows setup is user-launched and isolated from existing Hermes profiles:
pwsh -File tools/hermes/bootstrap/Install-JoblitHermes.ps1 `
-PackagePath <verified-package.zip> `
-ProfileName joblit-<opaque-account-hash> `
-ExpectedArchiveSha256 <published-sha256>After bootstrap succeeds, paste the one-time local API key into Extension settings → Local AI Beta. Production profile releases require a trusted Ed25519 signature; the current empty key registry intentionally fails closed until a real release key is provisioned.
flowchart LR
U[User] --> FE[Next.js UI]
U --> EXT[Chrome Extension]
FE --> API[Next.js API Routes]
API --> DB[(PostgreSQL via Prisma)]
FE --> AUTH[NextAuth]
EXT --> EXTAPI[Extension API Routes]
EXTAPI --> DB
EXT -->|auto-fill| ATS[ATS Application Forms]
EXT -->|learn| KB[Knowledge Base]
KB --> DB
FE --> FR[Create FetchRun]
FR --> GH[GitHub Actions]
GH --> PY[Seek + JobSpy fetchers]
PY --> IMP[Secret-gated JobSpy Import API]
IMP --> DB
FE --> AIPATH[AI Tailoring APIs]
AIPATH --> PDF[LaTeX Render]
PDF --> DL[PDF Download]
FE --> BATCH[Batch Automation APIs]
BATCH --> AIPATH
Domain vocabulary lives in CONTEXT.md, while durable architecture decisions live in docs/adr/.
app/
(marketing)/ Landing, privacy, terms, get-extension
(auth)/ Login
(app)/ Protected workspace
fetch/ Job intake pipeline
jobs/ Jobs triage workspace
resume/ Resume studio + prompt rules
discover/ Curated learning videos
extension/ Token + knowledge-base dashboard
api/ Backend routes
ext/ Extension-specific APIs
admin/import/ Internal JobSpy import route (IMPORT_SECRET-protected)
chrome-extension/
src/
background/ Service worker, auth, API client, sync queue
content/ Content script, form detection, filling, widget
detector/ Field classifier, ATS adapters, form signature
filler/ Input simulator, form filler
widget/ Shadow DOM floating widget
recorder/ Submission recorder
popup/ Extension popup UI (React)
shared/ Constants, i18n, types, field taxonomy
lib/
api/ Client-side fetch helper
server/ Domain services (AI, PDF, prompts, persistence, observability)
shared/ Zod schemas, market/locale seam, shared config
prisma/ Schema + migrations
tools/ Fetcher integration (Seek + JobSpy), readme metrics, CI policy checks
test/ API + server test suites
- Node.js >= 20.10
- npm >= 10
- PostgreSQL database (Neon recommended; any Postgres 14+ works)
- Optional: Gemini API key, Vercel Blob token, Chrome 120+ for the extension
# 1. Clone and install
git clone https://github.com/ShousenZHANG/joblit.git
cd joblit
npm install
# 2. Configure environment
cp .env.example .env
# Edit .env: fill DATABASE_URL, AUTH_SECRET, OAuth credentials, etc.
# 3. Initialize database
npx prisma migrate deploy
npx prisma generate
# 4. Run dev server
npm run devOpen http://localhost:3000.
cd chrome-extension
npm install
npm run dev # HMR for active development
npm run build # Production build → chrome-extension/distLoad chrome-extension/dist as an unpacked extension at chrome://extensions.
| Command | Description |
|---|---|
npm run dev |
Start Next.js dev server |
npm run build |
Production build |
npm test |
Run all tests once (Vitest) |
npm run test:watch |
Tests in watch mode |
npm run lint |
ESLint |
npm run readme:metrics |
Refresh auto-metrics badges in this README |
npm run deps:policy |
Check repository dependency policy |
npm run deps:audit |
npm audit (production deps, high severity) |
npm run hermes:profile:test |
Validate the minimal stock-Hermes Joblit profile |
npm run hermes:package:test |
Test deterministic packaging and Ed25519 verification |
npm run hermes:package:build -- --staging <dir> --source-commit <sha> |
Build a deterministic profile package |
npm run hermes:package:verify -- --root <dir> --mode <integrity|digest|production> |
Verify profile package trust and content |
npx prisma migrate dev |
Apply database migrations in development |
npx prisma studio |
Database GUI |
Run a single test file:
npx vitest run path/to/file.test.tsA complete template lives in .env.example.
| Variable | Purpose |
|---|---|
DATABASE_URL |
PostgreSQL connection string (Neon serverless adapter) |
AUTH_SECRET |
NextAuth session signing secret |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET |
Google OAuth |
GITHUB_ID / GITHUB_SECRET |
GitHub OAuth |
IMPORT_SECRET |
Service secret for the internal JobSpy import route (/api/admin/import) |
FETCH_RUN_SECRET |
Auth for the fetch-run config callback |
APP_ENC_KEY |
Extension token encryption key (base64) |
LATEX_RENDER_URL / LATEX_RENDER_TOKEN |
External LaTeX render service |
| Variable | Purpose |
|---|---|
SEEK_FETCH_ENABLED |
Kill-switch for server-side Seek fetching (1 / true to enable). Off by default — Seek is unreachable from datacenter / CI IPs (Cloudflare blocks every endpoint); the supported path is the browser extension. See ADR-0003. |
GEMINI_API_KEY / GEMINI_MODEL |
AI provider |
BLOB_READ_WRITE_TOKEN |
Vercel Blob storage |
GITHUB_OWNER / GITHUB_REPO / GITHUB_TOKEN / GITHUB_WORKFLOW_FILE |
Fetch workflow dispatch |
JOBLIT_WEB_URL |
Public URL for the extension callback |
YOUTUBE_API_KEY |
Discover-page video pipeline |
CRON_SECRET |
Cron endpoint auth |
RSSHUB_URL / RSSHUB_JOB_ROUTES / GITHUB_CN_JOB_REPOS |
China job sources |
SENTRY_DSN |
Error reporting (when SDK is installed) |
External orchestration protocol for AI-assisted batch tailoring is documented in AGENTS.md. Summary:
- Fetch jobs and keep target roles as
NEW. POST /api/application-batcheswith scopeNEW.- Loop
POST /api/application-batches/:id/run-once(atomic claim + complete). - For each task: generate prompt, run external model, import result.
- Track progress with
GET /api/application-batches/:id/summary.
- 750+ tests across the web suites (Vitest), green on every push
- Test files live alongside sources (
*.test.ts/*.test.tsx) or intest/ test/api/covers API routes,test/server/covers domain modules- 80%+ coverage target for new code
- E2E with Playwright for critical user flows (planned; see
docs/plans/)
CI runs lint, dependency policy, full test suite, and (per-PR) Lighthouse against the Vercel preview URL with the budget defined in .lighthouserc.json.
- Recommended: Vercel + Neon (PostgreSQL)
- Configure all environment variables in the deployment platform
- Chrome extension is distributed as a
.zipfor sideloading or via the Chrome Web Store
The migration that removes the obsolete access-request schema is destructive, so existing environments must use a code-first drain sequence:
- Deploy the current application code without running the drop migration.
- Wait for every old application instance and serverless deployment version to drain.
- Run
npx prisma migrate deployagainst the environment database. - Remove the obsolete
ADMIN_EMAILSenvironment setting.
Fresh environments may run all migrations during initial provisioning because no older application instance can still reference the removed schema.
| Symptom | Fix |
|---|---|
GITHUB_DISPATCH_FAILED |
Verify GITHUB_TOKEN workflow permissions on the fetch repo |
| Low import volume | Increase fetch breadth or relax title/description excludes |
PROMPT_META_MISMATCH |
Re-download skill pack and re-copy the prompt |
| Extension fields not filling | Check token validity on the Extension page |
403 Forbidden on Vercel preview |
Disable Vercel deployment protection or use the custom domain |
Issues and pull requests are welcome. See CONTRIBUTING.md for the development workflow, commit conventions, and review expectations. Architectural decisions are tracked in docs/adr/ once a decision needs to outlive the PR thread.
If you find a security vulnerability, please follow the responsible disclosure process documented in SECURITY.md. Do not open a public GitHub issue for security reports.
Joblit is built on top of excellent open-source work:
- JobSpy — multi-board job scraping pipeline
- Next.js, React, Prisma, Tailwind CSS
- Radix UI primitives + the shadcn/ui layer
- Framer Motion, TanStack Query, Zod
- next-intl, NextAuth, Lucide
- LaTeX render service is built on the TeX Live toolchain