JobSync: a self-hosted job application tracker with an AI assistant and an MCP server
Self-hosted, open-source job application tracker and AI-powered career assistant. Helps job seekers manage their search journey with AI resume review, job matching, task logging, and application analytics, all while keeping your data private.
At a glance
- What is it?
- JobSync is a TypeScript and Next.js job search tracker that runs on your own Docker host, with AI resume review, job matching, and an MCP server for agents like Claude Desktop. Here is how it installs, what its AI assistant can and cannot see, and where it stops being the right tool.
- Who is it for?
- Adopt JobSync if you want a job tracker whose database is a SQLite file on your own machine and whose AI features can run against a local Ollama instance, and if you are willing to supply a tool-calling model. Do not adopt it if you need multi-user hiring workflows, a hosted service with no Docker, or AI features that work without configuring a provider.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What JobSync solves for a single job seeker
A job search generates a specific kind of mess: a list of companies, a set of resume versions, a pile of pasted job descriptions, and a growing sense of not remembering which resume went where. Spreadsheets handle the list and nothing else. Hosted trackers handle the list too, but they hold your resume and your application history on someone else's server.
JobSync is aimed at the person who wants both: structured tracking and AI assistance, on hardware they control. The README describes it as a "free, open-source companion for your job search" and lists the pieces: an application tracker with company, title, date and status fields; a monitoring dashboard for application activity and success rates; resume storage with PDF export in Simple or Professional templates; task and activity management with time tracking; an in-app AI assistant; and an MCP server for external agents.
The intended user is one person running one instance. The docker-compose file mounts a single SQLite database at /data/dev.db and the entrypoint creates one resume directory. Nothing in the repository layout suggests tenancy, team roles or shared pipelines.
How the app is put together: Next.js, Prisma, SQLite, and a docked chat panel
The stack is visible from the repository root. package.json declares Next.js with Turbopack for development on port 3737, Prisma as the database layer, the Vercel AI SDK with provider packages for OpenAI, Google, DeepSeek and OpenRouter, and @modelcontextprotocol/sdk for the MCP server. The Dockerfile is a three-stage Node 20 Alpine build that runs prisma generate, then npm run build, then copies Next.js standalone output into a runner image running as a non-root nextjs user.
The AI assistant is not a separate page. The README describes it as a chat panel that "docks to the side of the app instead of taking it over", so the job or resume you are looking at stays on screen while it works. Three entry points feed it: the Review button on a resume, and the Match with AI and Cover Letter buttons on a job.
The scope restriction is the most interesting design decision here. According to the README, the assistant reads your resumes and the single job currently on screen, and nothing else. It cannot list or search your jobs, and it cannot see tasks or activities. Pasted job postings are treated as untrusted text so that instructions embedded in a posting cannot make the assistant act on your data. That is a narrower surface than most chat-over-your-data products, and it is deliberate.
The MCP server is the other integration path. It exposes tools that let an agent add job applications and Question Bank entries from a chat, with your approval, and analyze a substantial job description against your default resume to save a match score.
Installing JobSync with Docker Compose and creating the first account
The README's Quick Start assumes Docker is installed and running. Clone the repository, enter it, and bring the stack up. The first startup builds the app image, which the README warns can take a few minutes, so an unreachable app immediately after the command is expected.
git clone https://github.com/Gsync/jobsync.git
cd jobsync
docker compose upWhen the build finishes, open http://localhost:3737 in a browser and create your account. That is the whole first-run flow: no external database to provision, no migration step to run by hand, because docker-entrypoint.sh handles startup and the compose file points DATABASE_URL at a file inside the mounted volume.
services:
app:
image: ghcr.io/gsync/jobsync:latest
ports:
- "3737:3737"
environment:
- DATABASE_URL=file:/data/dev.db
- TZ=${TZ:-America/Edmonton}
- NEXTAUTH_URL=${NEXTAUTH_URL:-http://localhost:3737}
volumes:
- ./jobsyncdb/data:/dataThat snippet is the shape of the shipped docker-compose.yml, trimmed to the keys that matter for a first deploy. Two of them are worth changing before you go further. TZ defaults to America/Edmonton, and the README says to set it on remote servers to avoid activity time shifts. NEXTAUTH_URL defaults to localhost; for a homelab or reverse proxy you change it to your server address, and .env.example notes that AUTH_TRUST_HOST is required when the app is not served from localhost.
AI keys are configured in Settings after signing in, not in the compose file, though the compose file does pass OPENAI_API_KEY, GEMINI_API_KEY, DEEPSEEK_API_KEY and OPENROUTER_API_KEY through from the environment. For a fully local setup, OLLAMA_BASE_URL defaults to http://host.docker.internal:11434, and the compose file adds a host-gateway mapping so the container can reach an Ollama instance on the host.
Choosing a model, and what happens when you have not
The assistant will not guess. The README states that you pick a model under Settings > AI Settings before using the panel, that it needs one supporting tool calling, and that the app will tell you rather than guessing if none is set. This is a hard dependency, not a soft preference: resume review, job matching, cover letter generation and the add-a-job-from-a-posting flow all route through the same assistant.
The README references a known-good models list in a section that the excerpt cuts off, so the exact model names are not something I can quote. Treat that as the first thing to check in the docs before you wire up a provider.
The cover letter behaviour is worth calling out because it differs from the usual overwrite pattern. Asking again produces a new letter rather than replacing the old one, and letters are saved to your documents. If you iterate on tone, you accumulate versions rather than losing the previous attempt.
The add-a-job flow is the one place the assistant writes to your database, and it does so through a confirmation card that shows the extracted company, title, location, salary and tags before anything is saved. The README is explicit that the description is stored exactly as pasted, not summarized. Nothing reaches the database until you press Confirm.
Where JobSync is the wrong tool, and what ENCRYPTION_KEY really costs you
The sharpest constraint is in .env.example, not in the feature list. ENCRYPTION_KEY is used to encrypt stored API keys for OpenAI, DeepSeek and the rest, and the file states it must be stable across restarts because changing it makes all stored API keys unrecoverable. There is no documented rotation path. Lose that value and you re-enter every provider key by hand; change it deliberately and you get the same result. Generate it with openssl rand -base64 32 and store it wherever you keep secrets, because the app will not recover it for you.
AUTH_SECRET is friendlier: deploy.sh and docker-entrypoint.sh auto-generate it, and .env.example shows the manual override commented out.
The second limitation is scope. If your job search is a team effort, or you want a shared pipeline where a recruiter and a candidate see the same records, JobSync does not model that. One SQLite file, one account created at first run, one resume directory under /data/files/resumes. There is no role system visible in the compose file or the Dockerfile.
The third is the browser floor. package.json sets browserslist to Chrome 111, Edge 111, Firefox 128 and Safari 16.4. On an older machine or a locked-down corporate browser, the app is not built for you.
Finally, the AI features are only as good as the provider you attach. Running against Ollama keeps everything local but puts the quality question on whichever model you pull; the README's known-good list exists precisely because not every local model handles tool calling well.
JobSync compared with a hosted tracker or a plain spreadsheet
The obvious alternative is a hosted job tracker: a SaaS account where you sign up, paste applications, and get a dashboard without touching Docker. The difference is not features, it is where the data lives and who operates the update path. A hosted tracker pushes new versions to you and holds your resume on its infrastructure. JobSync inverts both. Your applications sit in a SQLite file under ./jobsyncdb/data on your own disk, and updates are a command you run yourself.
The second alternative is the spreadsheet, and it is a real one. A spreadsheet handles the tracker part of JobSync completely, and it never asks you for an ENCRYPTION_KEY or a tool-calling model. What it does not do is match a resume against a pasted job description, extract structured fields from a posting, or expose an MCP server that lets Claude Desktop add a job from a chat. If those are the parts you actually want, the spreadsheet is not a substitute. If they are not, JobSync is more moving parts than the problem needs.
The third comparison is against wiring an agent directly to your own notes or database through MCP. That gets you the agent integration without the tracker UI, the dashboard, the resume PDF export or the task logging. JobSync bundles those, and the MCP server is one entry point into the same records rather than a separate product.
Updating, licence and the cost of running it
Updates go through a deploy script rather than a manual git pull and rebuild. The README gives a one-liner that fetches deploy.sh from the main branch and runs it with sudo, which pulls the latest changes and rebuilds. On Windows the equivalent is deploy.ps1 run from the project directory, because deploy.sh needs WSL or Git Bash.
curl -fsSL https://raw.githubusercontent.com/Gsync/jobsync/main/deploy.sh | sudo bash -sThat pattern means the script is fetched fresh each time, so you are running whatever is on main at that moment. The release history shows a steady cadence: v1.1.17 on 2026-08-17, v1.1.18 on 2026-08-23, v1.1.19 on 2026-09-06, with package.json already at 1.1.20. The repository is not archived and the last push was on 2026-09-10. Expect to update reasonably often if you want the fixes, and budget the rebuild time each round.
The licence is MIT, which is permissive and places few obligations on how you run or modify the code. That is a statement about the licence text, not legal advice; if you plan to redistribute a modified version, read the LICENSE file yourself.
The running cost is whatever your host costs plus whatever your AI provider charges. Running against a local Ollama instance removes the per-call cost entirely and keeps resume text on your machine. Pointing it at OpenAI, Gemini, DeepSeek or OpenRouter moves that text to the provider, which is a trade you should make consciously given the whole premise is data privacy.
Editorial conclusion
Adopt JobSync if you want a job tracker whose database is a SQLite file on your own machine and whose AI features can run against a local Ollama instance, and if you are willing to supply a tool-calling model. Do not adopt it if you need multi-user hiring workflows, a hosted service with no Docker, or AI features that work without configuring a provider. Before you commit, verify that your chosen model supports tool calling, that ENCRYPTION_KEY is set and stored somewhere you will not lose it, and that TZ and NEXTAUTH_URL match the machine you actually deploy on.
Frequently asked questions
What is JobSync and what does it do?
JobSync is a self-hosted, open-source job application tracker with AI features. It records applications, stores and exports resumes as PDFs, runs a monitoring dashboard, manages tasks and activities with time tracking, and provides an in-app AI assistant plus an MCP server for agents like Claude Desktop.
Is JobSync legit?
It is an MIT-licensed open-source project published on GitHub under Gsync/jobsync, with a live demo at demo.jobsync.ca and a homepage at jobsync.ca. Because you self-host it, your application data stays in the SQLite file on your own server rather than on someone else's infrastructure.
How do I install JobSync?
Install Docker, clone the repository, and run docker compose up from the project directory. The first startup builds the app image and can take a few minutes; when it finishes, open http://localhost:3737 and create your account.
Does JobSync require an API key for the AI features?
You need a model configured under Settings > AI Settings before using the assistant, and it must support tool calling. AI can run locally through Ollama, or through OpenAI, Gemini, DeepSeek or OpenRouter, with keys set in Settings after signing in.
Can JobSync connect to Claude Desktop?
Yes. The built-in MCP server lets agents like Claude Desktop add job applications and Question Bank entries from a chat, with your approval, and analyze a substantial job description against your default resume to save a match score.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/gsync-jobsync)