Job Agent
AI AGENTS · BROWSER AUTOMATION · FULL STACK
An AI job-search assistant that finds jobs, scores them against a career profile, prepares applications and drives a real Chromium browser to fill forms — with human approval before anything is submitted.
Personal project — designed and built by Prince.
- ROLE
- Designed and built it end to end: architecture, agent state machine, browser automation, API, dashboard and test suite.
- STACK
- TypeScript · React · Vite · Express · Server-Sent Events · Playwright (Chromium)
- OUTCOME
- A working local MVP, backed by an end-to-end acceptance suite that drives real Chromium through the real orchestrator and database.
- LINKS
- Source code: [LINK REQUIRED]
01BRIEFING
Job applications are multi-page forms that differ on every site. Naive automation breaks on custom dropdowns, conditional questions, SPA navigation and validation errors — and, worse, reports success when it didn’t fill anything.
02OBJECTIVE
Automate the tedious parts — finding, scoring, filling — while never inventing qualifications, never bypassing CAPTCHAs or login walls, and never submitting without approval.
03ROLE
Designed and built it end to end: architecture, agent state machine, browser automation, API, dashboard and test suite.
04TECHNOLOGY
- TypeScript
- React
- Vite
- Express
- Server-Sent Events
- Playwright (Chromium)
- Prisma
- PostgreSQL
- Docker Compose
- Vitest
- OpenAI-compatible LLM API
05ARCHITECTURE
INTERFACE
- apps/web · React + Vite dashboard
- Live agent log over SSE
API
- apps/server · Express
- Agent orchestration
- Job-source adapters
AGENT
- State machine
- Page & question observers
- Interaction engine
- Navigation
- Debug recorder
INTELLIGENCE
- AIProvider → OpenAI-compatible | Mock
- Ranking · dedupe · field mapping
DATA
- Prisma
- PostgreSQL
TEST BED
- apps/mock-career-site
- Every hard form pattern, one route each
- Every browser interaction goes through one InteractionEngine: it fills a field, reads it back and retries with a different strategy if the read-back disagrees.
- Application state survives every page change and is persisted after each transition, so a server restart can resume a run.
06CHALLENGE
- Real application forms are adversarial by accident: radio groups in fieldsets, JavaScript dropdowns with no <select>, async autocompletes, fields that only render when scrolled into view, conditional questions, server-side validation and SPA navigation with no URL change.
- An agent that clicks “Next” and gets HTTP 200 can look successful while having filled nothing.
07SOLUTION
- Built a mock career site that implements each of those patterns on its own route, so every failure mode can be tested in isolation.
- The agent walks one page at a time: observe → detect questions → decide answers → fill → verify by reading back → check validation → find the forward control → wait for a real page change → re-observe.
- High-risk questions — work authorisation, visa, salary, legal attestations, demographics — are never auto-answered. CAPTCHAs and login walls pause the agent for the human. A submission only counts with positive evidence: a confirmation sentence or number.
- Loop detection watches page and question signatures; a repeated state stops the run, captures diagnostics, attempts one recovery, then asks the human.
08RESULT
- The e2e suite asserts every stage separately — job opened, analysed, questions detected, answers generated, fields filled, fields verified, page changed, resume uploaded, review reached, approval required, submitted, confirmation recorded. A run that returns 200 without filling anything fails.
- Per-run telemetry: a screenshot, DOM, visible text and structured snapshot per step, plus a JSONL log of prompts, answers, actions and verification results.
09EXPERIENCE
No public demo link yet. [DEMO / REPO LINK REQUIRED]
RELATED LAB EXPERIMENTS
10REFLECTION
The most important feature of an agent is knowing when to stop. Most of the engineering went into pausing, refusing and proving — not into clicking faster.VERIFY — Unverified — only in: Drafted copy — confirm voice
TECHNICAL LAYERWhy this stack · trade-offs · performance · implementation
WHY THIS STACK
- Playwright drives real Chromium with a persistent profile, so browser sessions live in the profile, not the database — no website passwords are stored.
- Server-Sent Events stream every agent action to the dashboard as it happens.
TRADE-OFFS
- Semi-automatic by default with auto-submit off: slower than a fully autonomous agent, but no application leaves without a human seeing it.
- A pluggable AIProvider with a mock implementation, so the whole pipeline — tests included — runs without an API key.
PERFORMANCE
- Action, retry, navigation and time limits are enforced on every run.
IMPLEMENTATION
- New job boards are JobSourceAdapter implementations; a site that blocks automation returns BLOCKED_REQUIRES_USER instead of attempting evasion.