求职记忆层服务

为求职者提供持久化求职上下文管理,统一维护简历、求职管道、面试记录、人脉与作品集,并通过桌面端、云端、移动端及 MCP、WebMCP、HTTP 接口把这套能力开放给 AI 助手和自动化流程,让用户在求职全流程中无需重复说明背景。

  • by JustLikeFrank3
  • Python
  • 混合部署
  • 7 星标
  • 更新于
在 GitHub 查看 JustLikeFrank3/jobContextMCP

使用说明

jobContext

The memory layer for your job search: a desktop app, a hosted cloud workspace, and a mobile companion built on one capability layer — with a conference badge client for your lanyard. Your resume, pipeline, interview history, outreach context, and portfolio live as structured context that persists across sessions — AI assistants (GitHub Copilot, Claude, Cursor, Windsurf) plug in over the Model Context Protocol, in-browser agents (ChatGPT desktop's browser, Chrome origin trial, Edge preview) drive the dashboard itself over WebMCP, and the dashboard, CLI, and mobile app drive the same tools over HTTP. You never re-explain yourself from scratch.

Built in Python with FastMCP, FastAPI, SQLite (dual-write JSON audit trail), a React dashboard, WeasyPrint/LaTeX PDF export, and pluggable LLM generation (OpenAI, Azure AI Foundry, Anthropic Claude, or local Ollama — all BYOK, or run keyless and let your AI client do the writing).

The agent is optional. MCP servers are protocol-driven capability layers — any client that speaks the protocol can call them. jobContext ships a CLI (cli.py) that invokes the tool surface directly from the terminal, no AI client required. Automation scripts, CI pipelines, cron jobs, the web dashboard, and the mobile app consume the same capabilities as Claude or Copilot. The AI is one type of client, not the only one.

Three ways to run it — desktop creates knowledge, mobile captures reality, cloud synchronizes:

What For
Desktop Tauri 2 app with embedded chat, one-click MCP connect, local SQLite Daily driver — everything stays on your machine
Cloud Multi-tenant AKS deployment behind Entra ID (jobcontext.ai) Remote MCP for Claude.ai/Cursor + in-browser agents via WebMCP (ChatGPT, Chrome/Edge), sync hub, always-on evals
Mobile Expo companion app with share-sheet capture Queue + assess jobs from your phone, Career Inbox

TL;DR

jobContext keeps your job-search context structured and persistent, and exposes it every way you work: MCP tools for AI assistants, HTTP APIs for automation, a web dashboard, a desktop app, and a mobile companion.

12 MCP tools 113 domain actions behind them
2954 passing tests Resume + cover letter generation with a deterministic truth gate
SQLite persistence + JSON audit trail Job fitment analysis with persona lenses
Local RAG semantic search Interview prep + debrief logging
Desktop app (macOS · Windows · Linux) Outreach + relationship tracking
Azure AKS multi-tenant deployment Three-layer eval framework with LLM-as-judge
Journal-based desktop ⇄ cloud sync Prometheus + Grafana observability

Works with: GitHub Copilot · VS Code · Claude Desktop · Claude.ai · Cursor · Windsurf · in-browser agents via WebMCP (ChatGPT desktop, Chrome origin trial, Edge) · HTTP clients · CLI automation

Jump to: Desktop · Mobile · Conference badge · Dashboard & output · Tool surface · Truth & evals · Setup · Configuration · Docs · Releases


Why I Built This

I got laid off and started using AI assistants to manage my job search. Every new session started from zero. I was re-explaining my resume, my pipeline, which companies I'd already talked to, what my STAR stories were, how I was holding up. The context overhead was brutal on top of everything else.

I built a few tools to stop re-explaining myself. They grew into this.

If you're in the same situation, it's yours.


jobContext Desktop

The whole platform as a native app — no terminal, no Python, no account. Download, drag to Applications (or run the installer), double-click.

⬇ Download the latest desktop release — look for the newest desktop-v* tag.

Release channels: desktop installers ship as desktop-v* beta prereleases, separately from the cloud product's v* releases. Branch CI artifacts and cloud deployments are not desktop releases: the app bundles its own frontend and backend, so newer changes on main reach installed apps only through a new desktop build. Read the selected release's notes for its exact source version, included changes, and platform installers.

Platform File Notes
macOS (Apple Silicon) jobContext_*_aarch64.dmg Signed + notarized
macOS (Intel) jobContext_*_x64.dmg Signed + notarized
Windows jobContext_*_x64-setup.exe Per-user install, Authenticode-signed (Azure Trusted Signing; SmartScreen may still warn while the new certificate builds reputation)
Linux .AppImage / .deb AppImage auto-updates; deb is manual

On top of the server you get an embedded AI chat over your own job-search data (OpenAI/Anthropic BYOK or local Ollama), one-click MCP connect for Claude Desktop / VS Code / Cursor, cloud workspace import/export, desktop ⇄ cloud sync, the eval loop on your own applications (author a golden set, run the truth suite, triage flagged claims — same screen as the cloud), Oura readiness, and automatic updates. Everything stays on your machine: local SQLite, loopback-only server, keys in your local config.

Home: the same command center as the cloud, running against local SQLite Chat: embedded AI over your own data — here on a local Ollama model, no keys, no cloud

Architecture, build docs, and the full decision log: desktop/README.md.


jobContext Mobile — iOS beta (TestFlight)

The Expo companion app, now in TestFlight beta. Desktop creates knowledge, mobile captures reality: share a job posting from Safari or LinkedIn straight into your pipeline (pages are extracted on-device, so it reads postings that block datacenter IPs), triage what's awaiting assessment, log a wellbeing check-in from the couch. It talks to your cloud workspace with an API key from the dashboard's API Keys tab — paste it once into Settings and it lives in the device keychain. Everything it captures syncs back to desktop.

Restoring your context Home: today's priority + readiness Pipeline: assessed vs awaiting Wellbeing: check-ins + Oura

Screens, capture flow, and build/ship docs: mobile/README.md.


jobContext Conference Badge

The GitHub Universe 2025 Pimoroni Tufty 2350 "Tufty Edition" runs a MicroPython client in badge/jobcontext/. It is another interface to your workspace, not a separate job-search database or an on-device LLM.

  • Search and capture: search your pipeline by company or role, discover open positions through the server's configured search provider, and add a selected opening to your pipeline.
  • Generate from your lanyard: choose a resume, cover letter, or both, select the layout and colour, and queue generation on the server. The badge polls compact work status and can notify you after you leave the waiting screen; open the generated files in the dashboard's Materials screen.
  • Wearable contact card: an optional name/title/link card alternates with a vCard QR code, alongside self-playing Tetris. Multi-network Wi-Fi settings support configured home, hotspot, and conference networks.

Device limits: text entry uses the UP/DOWN/A/B/C buttons. Bluetooth keyboard input is scaffolded but not implemented; the probed stock firmware lacks the pairing/bonding support it needs. Search and generation need Wi-Fi and a reachable server; the badge is not an offline generator. Use the supplied installer to precompile the app for its constrained memory.

Credential boundary: use a badge-scoped API key, never a full-access key. It is limited to /api/badge/* and cannot access MCP or the dashboard. The badge's mountable filesystem stores credentials in plain text, and its MicroPython HTTPS client does not verify server certificates; use a trusted network and revoke the badge token after the event.

Start with the device setup and button guide; see the API and scoped-key design for the server implementation. Without the badge, use the authenticated phone/laptop conference fallback, which reuses the same discovery and background-generation APIs with saved template choices and recovery controls. The fallback guide includes a live-rehearsal checklist and locally saved PDFs as the no-network escape route; software tests are not proof of a successful live hardware or provider-backed rehearsal.


Output

The dashboard

The same React SPA serves the desktop app and the cloud (app.jobcontext.ai) — these captures are the live cloud workspace, synced from desktop and mobile. Screens: Home, Pipeline, Job Hunt, Materials, Interviews, People (with a liveness-aware follow-up queue), Posts, Rejections, Wellbeing, Evals (your own golden set, run history with scoring visuals, A/B/C/D triage, judge picker), Chat (desktop), Settings, and API Keys.

Home: active/in-flight counts, dismissible priorities, daily digest, and Oura readiness driving "today's move".

Pipeline: intake → assessment (fitment score + signals) → generate → queue apply, with per-job templates and AI edit dialogs Job Hunt Tracker: applications kanban from outreach through offer
Wellbeing: mood/energy check-ins beside Oura readiness Settings: AI provider status, Oura connection, one-click workspace export

Generated documents

Generated from plain .txt files — no design tools. Templates live in templates/ and render via WeasyPrint; an owner-only LaTeX pipeline (Tectonic) handles typeset output.

Resume template gallery

4 layout formats × 5 color themes = 20 variants. All consume the same resume data; only the presentation changes. Template and theme are selected per-job in the pipeline.

Sidebar resume Sidebar cover letter
Two-column: contact/skills sidebar + experience/projects main Matching sidebar layout for the cover letter
Modern resume Modern cover letter
Single-column, ATS-friendly, clean typography Clean header band, flush prose paragraphs
Executive resume Executive cover letter
Centered letterhead, serif, achievement-focused Matching executive letterhead
Portfolio resume Portfolio cover letter
Projects-first, GitHub-prominent, technical profile Accent-strip header, project-centric intro

Themes: Navy (default) · Slate · Forest · Warm · Classic

⚠️ No template selected? If no template preference is saved in the pipeline, output falls back to the legacy format — Courier New, monospaced, hacker-tag header/footer. It's a genuine aesthetic choice if you want it. But if you haven't actively chosen it, your recruiter may have thoughts.

Legacy resume Legacy cover letter

Select a template in the pipeline and this will never happen to you.


The Tool Surface

12 consolidated domain tools, 103 actions. Each tool takes an action parameter; its docstring documents every action's required and optional parameters. Full reference with per-action tables: docs/tools.md.

Tool Actions Covers
applications 10 Pipeline status, evaluation queue, fitment assessments, application events
job_search 6 Open-web search (Google Jobs), Greenhouse/Lever/Ashby/Recruitee company boards, URL scraping
documents 17 Resume/cover-letter generation (sync, or background submit-and-poll for short-timeout agents), truth-gate provenance report, PDF + LaTeX export, diffs, strategy
materials 9 Master resume (read + audited in-place edit), saved materials, semantic search
interviews 9 Debrief logging, company process context, prep docs, cheatsheets
people 10 Contacts, referral chains, outreach drafting/review, cross-reference queue
stories 10 Personal stories, STAR context, writing-tone profile
wellbeing 7 Mood/energy check-ins, Oura readiness, HBDI profile
brand 7 LinkedIn post pipeline + metrics, GitHub/portfolio stats, skill scans
insights 8 Daily/weekly digests, session context, rejection funnel, comp comparison, eval-suite results
certification 8 Weekly work-search certification reports, employer directory, portal-ready exports
workspace 2 Workspace diagnosis and zero-manual-setup creation

A coverage test guarantees every capability of the historical 88-function surface is reachable through the facades; JOBCONTEXT_LEGACY_TOOLS=1 restores the per-function surface if a client needs it.

WebMCP — the dashboard is itself an agent surface

On the cloud dashboard, the same 12 tools are also registered as in-page WebMCP tools (document.modelContext, the W3C Web Machine Learning CG draft). An in-browser agent — ChatGPT desktop's built-in browser, Chrome's origin trial, Edge preview — can drive your whole workspace while you're on the site, signed in as you: no connector setup, no OAuth dance, no second tool surface. The bridge (frontend/src/webmcp/) fetches tools/list from /mcp and registers each tool verbatim, so it can never drift from what MCP clients see; calls ride the same-origin session cookie, and a CSRF guard ignores that cookie on cross-site /mcp requests so a hostile page can't ride your session. Security model, browser enablement (origin-trial tokens), and design notes: docs/webmcp.md.

Architecture

flowchart LR
    subgraph Clients
        AI["MCP clients<br/>(Copilot · Claude · Cursor)"]
        WMCP["In-browser agents<br/>(ChatGPT · Chrome OT · Edge)"]
        WEB["Dashboard SPA + mobile app"]
        BADGE["Conference badge<br/>(MicroPython · scoped API key)"]
        CLI["cli.py / scripts"]
    end
    subgraph Server
        TOOLS["12 MCP / CLI tools"]
        HTTP["FastAPI transport<br/>REST + SSE + /mcp"]
        WORK["Control plane<br/>(durable work_items)"]
        GATE["Provenance truth gate"]
        EVALS["Eval framework<br/>(per-tenant golden set · judge · triage)"]
    end
    subgraph Storage
        DB[("SQLite per partition")]
        WS[("Workspace files")]
        SYNC["Journal-based sync"]
    end
    AI -->|stdio / streamable-http| TOOLS
    WMCP -->|"WebMCP bridge<br/>(document.modelContext)"| WEB
    WEB --> HTTP
    BADGE -->|/api/badge/*| HTTP
    CLI --> TOOLS
    HTTP --> TOOLS
    HTTP --> WORK
    TOOLS --> GATE
    TOOLS --> DB
    TOOLS --> WS
    DB <--> SYNC
    WORK --> EVALS
    EVALS --> WS

Every tenant's data lives under DATA_FOLDER/users/{oid} with per-request context routing; background work goes through a durable control plane so it can never run against the wrong partition (docs/control-plane.md). Desktop and cloud stay consistent through journal-based bidirectional sync (docs/persistence.md).


Truth, Evals & Observability

Provenance gate — a deterministic truth check on every generated document: numeric claims (percentages, dollar amounts, multipliers, years) must trace to the master resume, stories, or JD, or the run is flagged — an LLM reviewer checks quality, this checks truth. Verdicts surface in the dashboard (violations modal) and Grafana; in-place master-resume edits are audit-logged so an agent can't legalize a fabricated claim by editing the source. Details: docs/generation.md.

Eval framework — three layers in evals/: declarative tool evals through the exact MCP dispatch path (a <95% smoke pass rate blocks deploys in CI), scoring rubrics with hard thresholds, and an adversarial LLM-as-judge over a committed golden dataset with N-run variance analysis (hallucination rate, verdict flips, baseline deltas). The judge itself is measured, not trusted: a planted-error fixture corpus records per-class catch rates against a synthetic master resume, blind human labels on the golden entries calibrate judge scores per dimension, and every run cross-checks the judge's hallucination list against the provenance gate's record. The ground truth is versioned too: every run stamps a content hash of the exact master bundle it measured against (master_sha), baseline deltas attest whether they compare the same master, the trend charts mark master changes, and the evals page warns when stored scores describe ground truth that has since changed — so "were these two runs measuring the same thing?" is a field comparison, not forensics. The judge can run on a separate provider/model from the generator. Runs from the CLI, or server-side via the control plane on a nightly schedule. Details: docs/evals.md.

Your own eval loop — the suite is also a product surface, not just an operator tool: the Evals screen (web and desktop — the Tauri shell wraps the same dashboards) lets any tenant author their own golden set by pasting 3–5 real job descriptions, run the truth suite against their own master resume, and triage every flagged claim A/B/C/D. The D ruling ("true but undocumented") is the loop's teaching moment — most first-run flags point at gaps in the master resume, and each documented D converts a recurring flag into citable material on the next run. The judge is configurable per tenant (a cheaper model is a legitimate cost choice for a personal trend line), with calibration labels that name exactly what was measured and on which corpus — an uncalibrated judge is labeled as one, never dressed up as the calibrated default. A bring-your-own judge key is write-only toward every page and encrypted at rest. The screen holds two durability guarantees, both incident-tested: a write either lands or fails loudly with your input intact, and a launched run always resolves to a state you can see — stored results, a visible failure (including "interrupted by a deploy; provider calls may have been billed"), or visibly in progress across reloads.

Observability — a dependency-free metrics registry exposes Prometheus counters for requests, LLM calls/tokens, work items, evals, and provenance verdicts at /metrics; dashboards-as-code under k8s/monitoring/ render them on an always-on wallboard (a Raspberry Pi running k3s + Prometheus + Grafana, federating the AKS cluster and scraping the workstation's local-LLM exporter).

Production — jobcontext.ai on AKS Local LLM — whatever model the workstation is serving (llama.cpp/ollama) + desktop app
Golden-dataset judge scores, variance, alerts Truth-gate verdicts (the red pass rate is the gate catching a local model fabricating)

Setup

Option A — Desktop app (no terminal)

Download, install, launch. The app provisions its own workspace, walks you through AI provider setup (or none), and wires MCP clients with one click.

Option B — Local server

git clone https://github.com/JustLikeFrank3/jobContextMCP.git && cd jobContextMCP
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt

# MCP stdio server (what AI clients spawn)
.venv/bin/python server.py

# Or the HTTP server: REST + dashboard + MCP Streamable HTTP at /mcp
PORT=8000 .venv/bin/python -m transport.http.main

Smoke-test the tool surface:

.venv/bin/python -c "import server; print('OK,', len(server.mcp._tool_manager.list_tools()), 'tools')"
# Expected: OK, 12 tools

Then connect a client — for VS Code, add a stdio entry to .vscode/mcp.json and restart the server from the MCP panel; the Output pane should show Discovered 12 tools. Per-client walkthroughs (VS Code, Claude Desktop, ChatGPT desktop, Cursor, Windsurf): docs/client-setup.md and docs/setup-claude-desktop.md.

There's no manual JSON authoring: ask your AI client to run workspace(action="check"), then workspace(action="setup") with your details — it creates the directory tree, seeds the data files, and writes config. Feeding the system well (stories, tone samples, reference materials) is what makes generation good: docs/generation.md.

Docker works too: docker compose run --rm jobcontextmcp (stdio) or MCP_TRANSPORT=sse docker compose up. See Dockerfile and docker-compose.yml.

Option C — Cloud (AKS) or self-hosted Kubernetes

The hosted deployment (jobcontext.ai) runs the HTTP server multi-tenant on AKS behind Entra ID: any Microsoft account can be invited as a guest and gets an isolated partition on first login; MCP clients (Claude.ai, Cursor, VS Code) connect over Streamable HTTP with OAuth (dynamic client registration + PKCE proxied to Entra). The dashboard is itself agent-usable: it republishes the same tools in-page over WebMCP (document.modelContext), so an in-browser agent — ChatGPT desktop's built-in browser, Chrome's origin trial, Edge preview — can drive your pipeline while you're signed in, with no connector setup. Deploys are CI-driven with an eval smoke gate. Manifests in k8s/; full guide: docs/aks-deployment.md.

Self-hosting without Azure: a disposable local k3d cluster or single-node k3s (proven on a Raspberry Pi 4) — docs/local-cluster.md.


Configuration

Everything the code reads — env vars, config.json keys, feature flags, per-deployment defaults — is documented in docs/configuration.md. Highlights:

  • LLM provider: llm_provider = openai · ollama · anthropic · foundry (BYOK for all; Ollama needs no key; Foundry can use AKS workload identity). Keyless mode still works — generation tools return a full context package for your AI client to write from.
  • Auth: single-tenant API_KEY, or Entra ID + per-user jcmcp_ personal access tokens (mobile, sync, scripts).
  • Storage: USE_SQLITE / SQLITE_ONLY switch the datastore; JSON dual-write is the audit trail.

Documentation

Guide Covers
docs/tools.md Every MCP tool, action, and parameter + the CLI
docs/api-reference.md Every HTTP endpoint, schema, auth requirement, error code
docs/http-api.md HTTP quick start, dashboard, LAN/phone mode, iOS Shortcut, API keys
docs/client-setup.md Connecting VS Code, Claude Desktop, ChatGPT, Cursor, Windsurf
docs/webmcp.md WebMCP bridge: in-browser agents driving the dashboard, CSRF model, browser enablement
docs/generation.md Generation modes, provenance gate, personas, PDF export, feeding the system
docs/evals.md Three-layer eval framework, LLM-as-judge, nightly runs, CI gate
docs/configuration.md Every env var and config.json key
docs/persistence.md SQLite/JSON tiers, migrations, partitioning, sync, backup/export
docs/local-development.md Dev workflow, venv vs Docker, SQLite locally, test gotchas
docs/control-plane.md Durable background work: design, incident history, roadmap
docs/aks-deployment.md AKS + Entra ID: deploy, app registration, isolation, QA env
docs/local-cluster.md k3d locally; k3s on a Raspberry Pi
desktop/README.md Desktop architecture, signing, updater, release pipeline
mobile/README.md Mobile companion: screens, capture, build/ship
badge/README.md Conference badge: hardware, installation, button input, contact card
docs/badge.md Badge API, scoped credentials, asynchronous generation, firmware tests
docs/conference-demo.md Phone/laptop fallback, template choices, recovery, live rehearsal checklist
CHANGELOG.md Full release history

Legal: privacy policy · terms of service. Agent instruction template for Copilot: copilot-instructions.example.md.


Recent Releases

Full details in the CHANGELOG.

  • v1.4.0 — Cover-letter edit dialogs with draft versioning, provenance verdict surfacing + violations modal, follow-up queue sanity (timeouts, dismissals), dismissible Home priorities, desktop beta updates.
  • v1.3.x — Desktop ⇄ cloud sync (journal-based, LWW, file manifests), workspace export/import, per-user API keys, Oura OAuth + encryption at rest.
  • v1.2 — jobContext rebrand, React SPA dashboard, QA environment, desktop app GA (signed macOS/Windows/Linux builds, auto-update).
  • v1.0–v1.1 — Multi-tenant AKS with Entra ID, per-user isolation, OAuth proxy for remote MCP clients, control plane P0, Prometheus/Grafana monitoring, mobile companion app.
  • Unreleased — WebMCP bridge (the dashboard republishes the tool surface as document.modelContext tools, so in-browser agents — ChatGPT desktop's browser, Chrome origin trial, Edge preview — drive your pipeline with no connector setup), connector resilience (refresh-token scope injection so hosted connectors survive token expiry, deploy-survivable MCP sessions, honest unknown-kid key handling), document generation routed through the control plane with provenance stamps — row id, prompt digest, model — on every artifact (P1), control-plane execution policy as data + per-row spend accounting (P2), Grafana eval panels click through to per-run detail, desktop ⇄ cloud sync fixes (personal context and tone samples, HBDI profile, story deletion). Per-tenant eval loop as a product surface (own golden set, A/B/C/D triage rulings that persist across runs, configurable judge with honest calibration labels, encrypted BYOK judge key, scoring visuals), versioned ground truth (every run stamps the master it measured; baselines, trends, and the page surface master changes instead of comparing across them silently), entailment critic with contradicted-finding enforcement in the revise pass, write durability + run visibility on the evals screen (failed writes keep your input and say so; launched runs always resolve to a visible state), backup delete propagation + restore-only-onto-empty-volume seed. Earlier: three-layer eval framework with adversarial LLM-as-judge, planted-error fixture corpus with measured per-class catch rates, blind human-label judge calibration, judge/generator model split, judge ⇄ provenance agreement tracking on the wallboard, server-side nightly eval runs, CI eval smoke gate, scraper guards against non-job pages, wallboard GPU rotation, mcp<2 pin.

What's next

Control-plane P3 scheduler (cron-style enqueuers for Oura autosync, weekly digest, follow-up nudges — document generation and per-row accounting/policy already run through the control plane as of P1/P2), automatic re-assessment on master-resume change, per-entry checkpoint/resume for eval runs (so a deploy costs one entry, not the run), richer mobile capture (WebView escalation for authwalled pages), voice debriefs. Tracked on the roadmap board.


Requirements

  • Python 3.12+ (3.13 works) for the server; Node 20+ only if you rebuild the dashboard SPA
  • macOS, Linux, or Windows
  • Optional: an LLM key (OpenAI / Anthropic / Azure AI Foundry) or local Ollama — keyless mode degrades gracefully
  • Optional: Docker, or kubectl + an AKS/k3s/k3d cluster for containerized deployment

License

MIT — see LICENSE.