Skip to main content

jobtrack

language: Python backend: FastAPI storage: SQLite license: MIT

A local job-search workspace built from the recruiting mail already in your Gmail. Find applications, assessments, interviews, offers, and rejections; follow each email timeline; and keep your next steps beside every opportunity.

Overview

Live demo: the real web UI with fictional applications from scripts/seed_demo.py. It is read-only and contains no data from a real inbox. Build it yourself with python scripts/build_demo.py site.

The app runs on your own machine with Python, FastAPI, and SQLite. It asks Gmail for one permission — gmail.readonly — so it can never send, delete, or modify mail. Classification works from offline rules and is optionally assisted by a local or hosted model.

Reads recruiting mail you already received Cannot send, delete, or modify mail
Stores everything in a local SQLite file Cannot reach your inbox without your approval
Runs on 127.0.0.1 with no external service Has no shared server or account; you can self-host your own copy

If you configure a hosted model provider, the email being classified is sent to that provider for the length of the request. Rules-only mode (--llm-mode off) and local models keep that content on your device. See SECURITY.md for what lands on disk.

Install

Python 3.10 or newer. From PyPI:

pipx install jobtrack      # or: uv tool install jobtrack

Or from a clone:

uv venv
uv pip install -e "."
source .venv/bin/activate

Or with plain pip:

python3 -m venv .venv && source .venv/bin/activate
pip install -e .

Either way you get a jobtrack command. Check it with jobtrack --help.

Authorize Gmail

There is no shared OAuth client here, and that is deliberate: your token goes to your machine, not to someone else's server. Google requires you to create your own client, which is the one part of setup that is not a single command.

  1. Open Google Cloud Console and create a project (or pick an existing one).
  2. Enable the Gmail API for that project.
  3. Under Google Auth Platform → Branding, set an app name and support email. Choose External.
  4. If the app is in Testing, add your own address under Test users. Skip this if you publish the app.
  5. Under Data Access, add exactly one scope: https://www.googleapis.com/auth/gmail.readonly
  6. Create an OAuth client ID of type Desktop app and download the JSON.
  7. Authorize:
jobtrack auth --credentials ~/Downloads/client_secret.json

A browser opens, you approve the read-only permission, and a token is cached at token.json (mode 600).

If your token stops working after about seven days: your OAuth app is in Testing, where Google expires refresh tokens quickly. This is not a bug. Either publish the app (Google Auth Platform → Publish app) or re-run jobtrack auth. It is the single most common problem people hit.

First sync

jobtrack serve

Then open http://127.0.0.1:8765.

Look before you import: open Sync options, set a lookback of 90 days and a limit of 50, and choose Preview first. That lists candidate messages and their classifications without changing anything. When it looks right, choose Sync Gmail. Your token and database are reused on every later start.

Applications

The layout is deliberately dense: charcoal surfaces, amber controls, monospace typography, compact top navigation, packed panels. The header toggle switches to a warm light theme, and the layout adapts to narrow screens without a separate mobile app. Press / to jump to application search.

  • Overview: current stages, active opportunities, interview count, response rate, an eight-week activity chart, role categories, follow-ups, and recent mail.
  • Applications: searchable list and board views; stage filters; CSV export; historical snapshots.
  • Activity: recent recruiting messages and persistent sync history.
  • Sync options: lookback, date bounds, message limit, custom Gmail search, whether to track mail you sent, and reclassification.
  • Settings: provider connections, masked API keys, live model discovery, and a multi-model review team.

One application, end to end

Every card is backed by the emails that produced it, and the status is derived from those events rather than typed in by hand — so "did they ever reply, or did I just wait?" is answerable from one panel.

Application detail

Each event shows its sender, arrival time, the snippet that earned its label, a link into the original Gmail conversation, and how it was classified. Correct it when the mail disagrees; the correction sticks across later syncs.

Command line

jobtrack sync --since 90 --limit 100          # import the last 90 days
jobtrack sync --track-sent --dry-run          # preview your own applications
jobtrack list --active                        # what is still open
jobtrack show 7                               # one application and its timeline
jobtrack stats                                # stage counts and response rate
jobtrack check acme                           # have I applied here before?
jobtrack add "Acme" --role "SRE" --date 2026-10-01   # an application that sent no email
jobtrack digest --days 7                      # what changed, and what's coming up
jobtrack report --anonymize -o retro.md       # Markdown retrospective
jobtrack details                              # read interview times from older mail
jobtrack export --format csv -o applications.csv
jobtrack serve --port 9000 --no-browser
jobtrack schedule install --at 08:00          # daily import via launchd or cron
jobtrack logout

--since accepts a number of days, 7d, 3m, 2y, or a calendar date. --as-of replays stored history without refetching Gmail. Global --db PATH selects another database and --json renders machine-readable output.

Read more

  • Architecture — how a message becomes an application, and the database invariants
  • Model analysis — providers, the four modes, and multi-model consensus
  • Metrics and corrections — response rate, attention cues, historical replay, syncing
  • HTTP API — every endpoint
  • SECURITY.md — the Gmail scope, on-disk files, and how to report an issue

Code map

  • sync.py handles import ordering, duplicate detection, preview mode, and classification handoff.
  • classify.py contains the offline relevance and lifecycle rules.
  • store.py persists applications and their email-event history.
  • insights.py builds the Insights page, digest, lookup, contacts, and follow-up drafts; details.py reads interview times, deadlines, and meeting links.
  • web.py exposes the local workspace; the web tests exercise timelines and API behavior.
  • Classifier tests use explicit email examples to check event labels and irrelevant-mail rejection.

The synthetic screenshots and rules-only mode provide a way to explore the project without sending email content to a model provider.

Development

uv pip install -e ".[dev]"
pytest -q
ruff check --select E4,E7,E9,F,I jobtrack tests

CI runs the same two commands on macOS and Linux across Python 3.10 and 3.12, and verifies the package builds.

Data lives in ~/Library/Application Support/jobtrack on macOS, ~/.local/share/jobtrack on Linux, and %APPDATA%/jobtrack on Windows. Override with JOBTRACK_HOME. Everything is git-ignored except .env.example.

The screenshots come from a seeded database of invented applications, so they carry no real personal data:

python scripts/seed_demo.py /tmp/jobtrack-demo.db
jobtrack --db /tmp/jobtrack-demo.db serve --port 8765

License

MIT. See LICENSE.

Metadata

Release files for jobtrack 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jobtrack 0.1.0
File Size Uploaded Provenance Actions
jobtrack-0.1.0.tar.gz 1.4 MB With provenance Details for jobtrack-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for jobtrack 0.1.0
File Interpreter ABI Platform Actions
jobtrack-0.1.0-py3-none-any.whl Python 3 none any Details for jobtrack-0.1.0-py3-none-any.whl

Total release size: 1.5 MB

Release files / jobtrack-0.1.0.tar.gz

Download URL jobtrack-0.1.0.tar.gz
Size 1.4 MB
Tags Source
SHA-256 checksum
How to use checksums
3e4dcdd6d0389b63c4960b29815fef1ec1bfab818b4772980292b7c4eb973540
BLAKE2b-256 checksum
How to use checksums
91cf66df35614f03cbfa073190567ed0928736df325a34eefc089ae7f2e6d243
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

Release files / jobtrack-0.1.0-py3-none-any.whl

Download URL jobtrack-0.1.0-py3-none-any.whl
Size 171.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4f7adf60a2c640c59604293be63c9d16f7d2f878005d1799fe4e3194b6cb7da4
BLAKE2b-256 checksum
How to use checksums
6af534b2e5c53077584120e95e26da95a9a5e6c09ab3138259ee4ec99b90cbbf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

Security for jobtrack 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for jobtrack-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page