
The job search, weaponized for the qualified.
The job search, weaponized for the qualified.
A citation-grounded AI job application copilot with Chrome extension, Gmail tracking, and three pricing tiers.
The challenge
Job seekers face a documentation problem, not an inspiration problem. They know what they want to say — they just need help saying it in language that matches the role, passes ATS screening, and sounds like a human wrote it. Tools that generate generic cover letters from nothing miss the entire point.
Jobpoise was built around citation-grounded generation: every piece of AI-generated content traces back to the candidate's actual experience, the actual job description, and named sources. No hallucinated accomplishments. No fabricated skills.
The challenge: building a product that is technically defensible (citation-grounded), commercially sustainable (Stripe paywall with sensible tier design), and usable in the actual workflow (Chrome extension for in-browser job applications and Gmail integration for application tracking) — all in a single Next.js monorepo.
How we built it
Monorepo: Next.js 15 with Turborepo — web app and Chrome extension as separate packages, sharing types and utility functions. AI layer: GPT-4 with structured prompting for citation-grounded generation. Every output includes a citation map linking content to input sources (resume bullets, JD requirements).
Chrome extension: Manifest V2, injects into major job board UIs (LinkedIn, Indeed, Greenhouse), enables one-click draft generation from the current JD. Gmail integration: OAuth-scoped Gmail API access to track sent applications, surface follow-up timing, and detect response patterns.
Billing: Stripe Checkout + Customer Portal. Three tiers — Drift (free) to prove value, Poise ($39/mo) for unlimited generations + Gmail tracking, Compose ($79/mo) for Chrome extension + priority processing. CI: 5 CI checks passing on main — type check, lint, unit tests, build, and E2E smoke test.
System map
How the pieces talk to each other.
Selected screens
Real product surfaces from the engagement — not stock illustrations.

Mock interview — behavioral set, real-time transcription, structured rubric scoring.
What shipped
Next.js 15 monorepo (web app + Chrome extension as packages). Citation-grounded AI generation (GPT-4 + structured prompt layer). Chrome extension v2 with job board injection. Gmail OAuth integration with application tracking dashboard.
Stripe Checkout + Customer Portal (3 tiers). 5 CI checks passing on main branch. Production deployment with auth, data persistence, and billing all live.
Results
Fully merged main branch — no open feature PRs blocking production. All 5 CI gates passing: TypeScript, ESLint, unit tests, build, E2E smoke. Stripe billing live and processing test transactions.
Chrome extension functional on LinkedIn, Indeed, and Greenhouse. Three-tier pricing model ready for go-to-market.
A monorepo with a web app and a browser extension, sharing types and utilities, can be built and maintained by a single engineer without sacrificing CI discipline. The citation-grounding architecture is the differentiator — it's what separates Jobpoise from a GPT wrapper with a job-shaped UI.
Talk to people on this work.
No fabricated quotes. Reference contacts are shared during discovery, with both parties' consent.
Engineering lead
Worked alongside on production trading systems for 5+ years. Available for technical reference calls — code quality, on-call discipline, incident behavior.
Founder
Engaged Sage Ideas for a Ship + Operate combination. Willing to talk about scope discipline, timeline accuracy, and what handoff actually looked like.
“An AI that lies about your resume is worse than no AI at all. Every claim it generates has to point at a line you actually wrote.”
What almost happened.
Every project has near-misses. Decisions that, if we'd kept going, would have shipped a hole. The list below is the diff between the version that almost made it to prod and the version that did.
Inline excerpts.
Trimmed, but real. These are the patterns that made the system survive Stripe retries, multi-tenant queries, and a Discord bot that won't hallucinate positions.
// lib/generate.ts — production excerpt
export async function generateBullet(
jd: JobDescription,
resume: ParsedResume,
): Promise<CitedBullet> {
const candidates = await llm.generate({
system: SYSTEM_PROMPT,
user: prompt(jd, resume),
schema: BulletSchema, // forces { text, citations: SpanRef[] }
})
// Reject any output whose citations don't resolve to real resume spans
for (const cite of candidates.citations) {
const span = resume.spans.get(cite.id)
if (!span) throw new HallucinationError(cite.id)
if (!candidates.text.includes(span.text.slice(0, 12))) {
throw new HallucinationError('paraphrase too loose')
}
}
return candidates
}