Jobsmith
A workspace for assessing job opportunities, tracking applications, and organizing a job search.

- Working app, open source (AGPL-3.0)
- Next.js, React, Postgres, Drizzle, Better Auth, Vercel AI SDK
One app for a whole job search: find and qualify roles, research the company, apply, prepare for each interview stage and debrief. It is self-hostable with your own database, and AI is optional.
The problem
A job search spreads across a tracker, company research, tailored documents and interview prep. Before Jobsmith those lived in separate prototypes and a folder of markdown files. Jobsmith puts every job on one board, gives each job one page, and gives the markdown a home. The first audience is product designers.
The board
Seven stages from Saved to Offer. Jobs move by drag, by a digit key from 1 to 7, or through a Move to menu that works for mouse and screen-reader users. Each move is announced. Below 768px the board becomes a list grouped by stage.

One page per job
A stage track, the next action, and tabs for the overview, documents, research and prep. Documents are versioned markdown. Marking one as sent locks it, and an edit to a sent or stale version forks a new version instead of overwriting it.

Intake from a link
Greenhouse, Ashby and Lever postings are read through their APIs. Other links are fetched as web pages, and LinkedIn needs pasted text. Duplicates are caught. The fetch only goes to public addresses on ports 80 and 443.
Companies
Each company with its jobs and their stage.

A bridge for outside work
A CLI (login, list, pull, push) and a token API let markdown written elsewhere land on the right job. Pushing the same folder twice reports it as unchanged.
Decisions
AI is an enrichment, never a gate
With no model configured, adding a job asks for the company and role by hand, and the hard filters from Preferences still run in code. When the model cannot read a posting, the job is saved with a notice to check its details.
Nothing is sent by accident
The AI provider has to be chosen on purpose. If it is unset, every other AI setting is ignored, so a leftover key in a shell never sends a posting anywhere. Posting text is never logged.
Fit in two parts
Hard filters run in code and answer at once. The model score runs after the response is sent. Score bands are relative to the user's own threshold, 70 by default with a 15-point mixed band.
One write path per concept
Drag, stepper, phone sheet, bridge, paste dialog and importer all call the same pipeline and document code, so a stage move means the same thing everywhere.
Privacy for a sensitive domain
People hide a job search from their employer. Signed-in pages carry no content analytics and no third-party scripts.
Research before prep
An interview in the next 72 hours with no research points to the Research tab first. A fit brief alone does not count.
Tokens only, checked in CI
A check fails on raw colors or arbitrary values outside the component layer, and the end-to-end suite runs an accessibility scan in light and dark.