- ✨ Introduction
- ⚙️ Tech Stack
- 🔋 Features
- 🤸 Quick Start
JobPilot is an autonomous, full-stack AI agent that transforms how technical job seekers find work using Adunza, and apply to roles. Powered by Next.js, Gemini, and Browserbase automation, the app dynamically customizes resumes and executes real browser application forms autonomously. More than just a utility, JobPilot serves as a masterclass in modern agentic engineering, utilizing five core open-source skills—/architect, /remember, /review, /recover, and /imprint—to demonstrate how a single developer with a structured system can rapidly ship durable, production-grade AI software.
- Next.js is a full-stack React framework that powers JobPilot's user interface, utilizing the App Router, Server Actions, and API Routes to deliver server-rendered components and high-performance client-side navigation.
- TypeScript is a strongly typed programming language that builds on JavaScript, ensuring strict type safety across the entire codebase and providing a maintainable environment for complex agent orchestration.
- Tailwind v4 is a utility-first CSS framework used for rapid UI development, providing a clean, responsive, and easily customized styling infrastructure.
- shadcn/ui is a collection of re-usable UI components built using Radix Primitives and Tailwind CSS, serving as the design system for the app's dashboard, tables, and job inventory views.
- OpenAI GPT-4o is a highly capable multimodal AI model that serves as the core intelligence engine, parsing job descriptions to compute match scores, tailoring resumes, and driving the form-filling automation logic.
- Stagehand is an AI-driven browser agent built on top of Playwright that uses LLMs to interpret page elements dynamically, allowing JobPilot to execute LinkedIn Easy Apply paths and handle external ATS form-filling.
- Browserbase is a headless cloud browser platform that manages infrastructure, session persistence, authentication states, and CAPTCHA solving so background jobs can run through realistic browser instances.
- InsForge is a comprehensive backend-as-a-service provider that supplies the relational PostgreSQL database to manage the job inventory, handles user authentication, and provides secure file storage for assets.
- PostHog is an all-in-one product analytics platform used to track user engagement, system performance metrics, and the success rates of automated application paths.
- Authentication: Google/GitHub OAuth with InsForge.
- Profile management: User profile, completion tracking, save/edit.
- Resume upload: Private PDF storage.
- Resume extraction: Gemini turns uploaded PDF into profile fields.
- Resume generation: Gemini + PDF renderer creates a clean resume.
- Job discovery: Adzuna finds tech jobs.
- Job matching: Gemini scores jobs against the user profile.
- Job listing: Filter, sort, search, paginate saved jobs.
- Job details: Full job view with match reasoning and apply links.
- Company research: Browserbase + Stagehand + Gemini creates interview prep dossiers.
- Dashboard: Stats, activity feed, and PostHog analytics.
- Analytics tracking: Approved PostHog events across key actions.
- Security: Protected routes, user-scoped database rows, private resume storage.
Follow these steps to set up the project locally on your machine.
Prerequisites
Make sure you have the following installed on your machine:
Cloning the Repository
git clone https://github.com/VCji21/jobpilot.git
cd jobpilotInstallation
Install the project dependencies using npm:
npm installSet Up Environment Variables
Create a new file named .env in the root of your project and add the following content:
NEXT_PUBLIC_INSFORGE_URL=https://9zb7h4wq.us-east.insforge.app
NEXT_PUBLIC_INSFORGE_URL=
NEXT_PUBLIC_INSFORGE_ANON_KEY=
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN=
NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
POSTHOG_PROJECT_ID=
POSTHOG_PERSONAL_API_KEY=
GEMINI_API_KEY=
ADZUNA_APP_ID=
ADZUNA_APP_KEY=
BROWSERBASE_API_KEY=
BROWSERBASE_PROJECT_ID=Replace the placeholder values with your real credentials. You can get these by signing up at: InsForge, Browserbase, Gemini, PostHog, Adzuna Running the Project
npm run devOpen http://localhost:3000 in your browser to view the project.
How It Works
Here’s how your JobPilot application works, step by step.
-
User Lands On Homepage
- The homepage explains JobPilot.
- User can click CTAs like
Get Started,Start for free, orFind Your First Match. - If logged out, CTAs go to
/login. - If logged in, CTAs go to
/dashboard. - The hero CTA tracks
landing_cta_clickedin PostHog.
-
User Signs In
- User goes to
/login. - They can sign in with Google or GitHub through InsForge OAuth.
- OAuth callback is handled by
/api/auth/callback. - After login, user is redirected to
/dashboard. - Protected pages are:
/dashboard/profile/find-jobs/find-jobs/[id]
- User goes to
-
User Manages Profile
- User opens
/profile. - The app loads their saved profile from InsForge.
- If no profile exists, it starts with empty fields and the account email.
- Profile includes:
- Personal info
- Work authorization
- Current title
- Experience level
- Years of experience
- Skills
- Industries
- Work experience
- Education
- Job preferences
- Profile completion percentage is calculated from required fields.
- Saving writes profile data to the
profilestable. - When the profile becomes complete for the first time, PostHog tracks
profile_completed.
- User opens
-
User Uploads Resume
- User uploads a PDF resume from
/profile. - Upload route:
/api/resume/upload. - Resume is stored in the private InsForge
resumesbucket. - Path is
{user_id}/resume.pdf. - The profile stores the private resume key in
profiles.resume_pdf_url.
- User uploads a PDF resume from
-
User Extracts Profile From Resume
- After uploading a resume, user can click
Extract from Resume. - Route:
/api/resume/extract. - The app downloads the private PDF from InsForge.
pdf-parseextracts text from the PDF.- Gemini reads the resume text and returns structured profile fields.
- The form is auto-filled.
- Extraction does not save automatically; user reviews and clicks
Save Profile.
- After uploading a resume, user can click
-
User Generates Resume From Profile
- User can click
Generate Resume. - Route:
/api/resume/generate. - The app loads the saved complete profile.
- Gemini writes polished resume content.
@react-pdf/rendererrenders a PDF server-side.- The generated PDF replaces the active resume at
{user_id}/resume.pdf.
- User can click
-
User Downloads Resume
- User clicks
Download Resume. - Route:
/api/resume/download. - The app reads the resume key from the user’s profile.
- It downloads the private file server-side.
- The browser receives the PDF without exposing a public storage URL.
- User clicks
-
User Finds Jobs
- User opens
/find-jobs. - They enter:
- Job title
- Location
- Clicking
Find Jobscalls/api/agent/find. - The app requires at least one saved target job title and one skill in the profile.
- A new
agent_runsrow is created. - PostHog tracks
job_search_started.
- User opens
-
Adzuna Discovers Jobs
- The backend calls Adzuna’s API.
- Searches are filtered to IT jobs.
- Supported country detection includes US, UK, Canada, and Australia.
- Each result is normalized into the app’s job format.
-
Gemini Scores Jobs
- Gemini compares each job against the user’s profile.
- It returns:
- Match score
- Match reason
- Matched skills
- Missing skills
- If Gemini fails or rate limits, the app still saves the job with:
match_score = null- Empty matched/missing skills
- A user-facing warning
- Each saved job tracks
job_foundin PostHog.
- Jobs Are Saved
- Jobs are saved in the
jobstable. - Each job belongs to the current user.
- Each job includes:
- Title
- Company
- Location
- Salary estimate
- Job type
- Source URL
- Apply URL
- Match score
- Match reason
- Matched skills
- Missing skills
- Found date
- User Browses Saved Jobs
/find-jobslists saved jobs from InsForge.- User can:
- Search by company or role
- Filter all/high/low matches
- Sort by match score, newest, or oldest
- Use pagination
- Unscored jobs show
Not scoredinstead of0%.
- User Opens Job Details
- Clicking a job opens
/find-jobs/[id]. - The app loads only jobs owned by the signed-in user.
- Job details show:
- Job title
- Company
- Match score
- Salary
- Location
- Job type
- Date found
- Match reasoning
- Matched skills
- Missing skills
- Job description
- Apply button
- User Researches Company
- On a job detail page, user clicks
Research Company. - Route:
/api/agent/research. - The app loads:
- The job
- The user profile
- Existing match data
- Browserbase opens a cloud browser session.
- Stagehand visits the company homepage and up to 3 useful internal pages.
- Gemini synthesizes a company dossier.
- Company Research Is Saved
- Research is saved to
jobs.company_research. - The dossier includes:
- Company overview
- Tech stack
- Culture
- Why this role
- Your edge
- Gaps to address
- Smart questions
- Interview prep
- Sources
- PostHog tracks
company_researched. - User can refresh research later.
- User Applies
- Job detail page has:
View Job PostApply Now
- Both open the external saved apply URL in a new tab.
- JobPilot does not auto-apply or fill application forms.
- Dashboard Shows Progress
/dashboardis protected.- If profile is incomplete, it shows the profile completion banner.
- It displays real stats:
- Total jobs found
- Average match rate
- Companies researched
- Jobs this week
- Dashboard Shows Recent Activity
- Recent activity is loaded from:
- Completed
agent_runs - Jobs with company research
- Completed
- It shows recent job searches and company research actions.
- Dashboard Shows Analytics
- Dashboard charts use PostHog Query API.
- Charts include:
- Jobs found over time
- Match score distribution
- Company research activity
- If PostHog read credentials are missing, charts show empty states instead of crashing.
- User Signs Out
- Authenticated pages show a Sign out button.
- Sign out calls
/api/auth/sign-out. - Session cookies are cleared.
- User is redirected to homepage.