career-fit-assistant
Generates GitHub profile README copy from career-fact bundles for GitHub profile presence and bio maintenance.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@career-fit-assistantCheck my fit for this job description and draft a cover letter if it's a good match."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
career-fit-assistant
A deterministic, fit-gated document generation engine exposed to AI assistants over MCP — refuses to draft a resume or cover letter when a job description's skill match falls below a Good rating, rather than producing a generic one. Built as three coordinated projects powering a real job-search workflow: Project 2 is the single source of truth for career facts, Projects 1 and 3 consume generated bundles from it.
This is a sanitized public snapshot. It's exported from a private working repo with the same architecture, replacing all personal data with a fictional example persona (
project-2-profile-learning-hub/Resume_Snapshot.md— "Sarah Ashford," a made-up person) and starting a fresh git history with no link back to that private repo. Clone it, install, and runpython3 -m cli.career_fit_api build— the whole pipeline — fit rating, resume/cover-letter generation, learning-plan PDFs — works end to end against the example data:git clone <repo-url> career-fit-assistant && cd career-fit-assistant python3 -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate pip install -e ".[docx,yaml,schema,pdf]" python3 -m cli.career_fit_api buildFor the MCP server (Claude Desktop integration), see the step-by-step setup in mcp_server/README.md.
Architecture
flowchart TB
subgraph Clients
Term["Terminal / Claude Code"]
Desktop["Claude Desktop / other MCP client"]
end
MCP["mcp_server/server.py\n(MCP tools)"]
CLI["cli/career_fit_api.py"]
P2["Project 2 — Profile & Learning Hub"]
P1["Project 1 — Application Engine"]
P3["Project 3 — Presence & Identity"]
Term --> CLI
Desktop --> MCP
MCP -->|calls cli.career_fit_api.main| CLI
CLI --> P1
CLI --> P2
CLI --> P3
P2 -->|profile-bundle.json| P1
P2 -->|presence-bundle.json| P3Two ways in: a terminal invokes cli/career_fit_api.py directly; an MCP client
like Claude Desktop calls mcp_server/server.py, which is a thin adapter
that builds the same argv the CLI would and calls cli.career_fit_api.main() —
see mcp_server/README.md. Either way, the CLI is the
single dispatcher into the three projects below.
Bundle model (v3 sequential): Project 2's profile-hub-bundle-generator skill compiles the four canonical source files into two bundles. Each downstream project reads its bundle directly — no network fetch, no cross-project file imports. Bundle regeneration is gated by 6 consistency checks (cert sync, AI-200 wording sync, gap closure, differentiator coverage, course count regression, badge URL format). The authoritative bundles are now produced as JSON: outputs/profile-bundle.json (PII-allowed) and outputs/presence-bundle.json (GitHub-safe).
Distribution: this public repo is a sanitized snapshot exported from a private working repo (andreak3779/claude-projects). app-engine-bundle.md contains PII and is gitignored, same as in the private repo. presence-bundle.md is committed and serves as the public-safe source of truth. Resume_Snapshot.md here is the fictional example persona, not real career data.
Related MCP server: ResumePilot MCP
Projects
project-1-application-engine/ — generates tailored job-application artifacts: gap analyses, resumes, cover letters, interview prep, salary research. Reads
outputs/profile-bundle.json. 13 skills, 4 DOCX templates, 5 reference docs.project-2-profile-learning-hub/ — source of truth for career facts, Pluralsight/MS-Learn learning history, and portfolio projects. 8 skills, 2 Python utility scripts (Pluralsight HTML parser, learning-plan PDF template), 8 markdown data files.
project-3-presence-identity/ — LinkedIn, GitHub, Jobgether, Indeed/ZipRecruiter, and Pluralsight profile updates. Reads
presence-bundle.mddirectly (GitHub's generator is the exception, readingoutputs/presence-bundle.json). 5 skills.
Each project has its own README.md and CLAUDE.md; the CLAUDE.md files document project-local conventions, the sync protocol, and PII rules.
Bundle generation
The single skill that owns all bundle regeneration lives in Project 2: skills/profile-hub-bundle-generator_SKILL.md.
It runs 6 sequential consistency checks before writing anything, and produces two output files in their canonical project locations:
Output | Path | PII | Git |
|
| yes (email, phone) | ignored |
|
| no | committed |
| repo root | yes | ignored |
| repo root | no | ignored |
Run it whenever any of these events happen:
Certification status changes (AZ-900, AI-200, …)
Gap status changes in
profile-facts.mdResume section edited
Portfolio project added or updated in
github-repos.mdA Pluralsight course closes a known gap
(Course count update only, no gap change → no regen needed)
See the skill file for the full sync protocol and consistency-check rules.
Fresh OS install
Start here after a clean OS install/reimage, before touching any individual project. There are two independent toolchains — Python (repo root + Project 2) and Node.js (Project 1) — but Node.js is only needed for one specific workflow, not for the CLI or MCP server. See the diagram below, then follow the numbered steps for your use case.
flowchart TB
subgraph Always["Always required"]
PY["Python 3.11+"]
VENV["repo-root .venv\npip install -e '.[docx,parser,yaml,schema,pdf]'"]
PY --> VENV
end
VENV --> CLI["CLI usable\ncli/career_fit_api.py\n(build, fit-check, generate-resume, ...)"]
VENV -->|"+ mcp extra"| MCP["MCP server usable\nmcp_server/server.py\n(Claude Desktop / container)"]
subgraph SkillOnly["Only for the live-chat SKILL.md workflow"]
NODE["Node.js >=10"]
NPM["cd project-1-application-engine\nnpm install"]
NODE --> NPM
end
NPM --> SKILL["Claude runs a SKILL.md directly in chat\ntemplates/*.js DOCX generation"]
CLI -. "generates DOCX in pure Python\n(shared/docx_layout.py) — no Node.js involved" .-> SKILLPython 3.11+ — check with
python3 --version. On Debian/Ubuntu the venv module ships separately:sudo apt install python3-venvif step 2 fails.Repo-root Python setup — see the quick-start block at the top of this file. Installs the monorepo CLI and its dependencies (
docx,yaml,schema,pdfextras) into.venv/.MCP server (optional, only if you use Claude Desktop) — see mcp_server/README.md. Adds the
mcpextra on top of step 2's venv.Project 2 Python deps — see project-2-profile-learning-hub/README.md. Only needed if you'll run
parse_pluralsight_html.pyorpdf-template.pydirectly; both packages' dependencies already overlap with the rootparser/pdf/docxextras.Node.js (Project 1 only, and only for the live-chat SKILL.md workflow) — skip this step entirely if you'll only use the CLI or MCP server:
generate-resume/generate-cover-letter/etc. generate DOCX files in pure Python (shared/docx_layout.py+python-docx, already installed by step 2'sdocxextra) and never shell out to Node.js. Node.js is only used when Claude runs a skill'sSKILL.mdinstructions directly in a chat session (not through the CLI/MCP), which shells out totemplates/*.jsfor DOCX generation instead. If you need that workflow: check withnode --version(any Node ≥10), install via your distro's package manager or nodesource if missing, thencd project-1-application-engine && npm install— see project-1-application-engine/README.md.Pre-commit hook (optional but recommended) —
bash scripts/install-hooks.shfrom the repo root. See Local pre-commit hook below.
Project 3 needs no local install — it only reads a committed markdown bundle.
CLI
A monorepo CLI lives in cli/career_fit_api.py. From the repo root:
python3 -m cli.career_fit_api build # regenerate JSON bundles
python3 -m cli.career_fit_api validate # run 6 canonical consistency checks
python3 -m cli.career_fit_api fit-check <jd.md> # inline fit table for a JD
python3 -m cli.career_fit_api gap-analysis <jd.md> # markdown gap-analysis report
python3 -m cli.career_fit_api generate-linkedin # LinkedIn profile copy
python3 -m cli.career_fit_api generate-github # GitHub profile README copy
python3 -m cli.career_fit_api generate-jobgether # Jobgether profile copy
python3 -m cli.career_fit_api generate-job-board # Indeed & ZipRecruiter profile copy
python3 -m cli.career_fit_api generate-pluralsight # Pluralsight profile copyUse python3 -m cli.career_fit_api <command> --help for each command's options.
MCP server
mcp_server/ exposes the same CLI commands as MCP tools for Claude Desktop or any other MCP-capable client — see mcp_server/README.md for install and setup.
Fit engine
shared/fit_engine.py is the deterministic rating engine used by fit-check and gap-analysis. It classifies each JD skill as production (match), portfolio (portfolio), coursework (course), or no evidence (gap) and derives an overall Strong / Good / Stretch / Pass rating. It handles multi-token phrases, years-of-experience prefixes, and a small alias map for common co-occurring terms (e.g., C# ↔ .NET, REST API ↔ ASP.NET Core Web API).
Ratings are driven by a weighted score where production evidence is worth more than portfolio or coursework: match=1.0, portfolio=0.7, course=0.4, gap=0.0. A required-skill score of 85%+ with 50%+ nice-to-have coverage yields Strong; 60%+ without gaps yields Good; any gaps but 30%+ weighted score yields Stretch; otherwise Pass.
The engine handles:
Alias expansion — common co-occurring terms (e.g., C# ↔ .NET, REST API ↔ ASP.NET Core Web API) via
shared/aliases.json.Compound splitting — slashes, semicolons, "and"/"or" in JD phrases are split so partial matches register.
Years-prefix normalization — "5+ years of C#" becomes "c#" before matching.
Genuine-gap fallback — skills explicitly listed as known genuine gaps can still earn
portfolioorcoursestatus if the gap record says so.
Alias data lives in shared/aliases.json. The registry is loaded at import time, and validate confirms it is well-formed. To add a new synonym pair, edit that JSON file and re-run validate; no Python code changes are required.
Tests
Run the full suite with:
python3 -m pytest tests/ -qThe suite covers bundle loading, the fit engine, JD parsing, and CLI smoke tests for fit-check, gap-analysis, and all five profile-update generators (generate-linkedin, generate-github, generate-jobgether, generate-job-board, generate-pluralsight).
CI
.github/workflows/ci.yml runs:
DOCX template syntax check (project-1)
PII guard on
app-engine-bundle.mdPluralsight JSON validation
JSON bundle build (Project 2)
6 canonical bundle-validation checks plus alias-registry shape check
pytestsuiteCLI end-to-end smoke tests (
build,validate,fit-check,gap-analysis,generate-linkedin,generate-github,generate-jobgether,generate-job-board,generate-pluralsight)
This workflow is workflow_dispatch-only (no push/pull_request trigger) — deliberately, to avoid billed GitHub Actions runner time on every commit. That means none of the above runs automatically. The local git pre-commit hook below is the actual enforcement for the two checks that matter most day to day (bundle consistency, skill hardcoding) — run the full CI workflow by hand before anything you especially want double-checked.
Local pre-commit hook (zero-cost substitute for CI-on-push)
One-time setup:
bash scripts/install-hooks.shThis installs scripts/hooks/pre-commit into .git/hooks/pre-commit (git hooks aren't tracked by git themselves, so this copy step is required once, and again any time scripts/hooks/pre-commit changes). It then runs automatically on every git commit and blocks the commit if ruff check, check_skill_hardcoding.py, check_bundle_freshness.py, or validate.py (when a bundle exists) fail. It intentionally skips the full pytest suite and mypy — those are quick enough to run manually before pushing but slower than what belongs on every commit. Bypass with git commit --no-verify if you're deliberately committing through a known failure.
Data flow scripts
Project 2 has two personal-utility Python scripts:
parse_pluralsight_html.py— parses a Pluralsight HTML export, merges intodata/pluralsight_learning_history.json(authoritative), and writes a regenerated output JSON. Run after every Pluralsight sync. No automated tests — manually spot-checked againstpluralsight-courses.mdafter changes. This snapshot doesn't includedata/pluralsight_learning_history.jsonitself (personal learning-activity data, not needed by the build pipeline or test suite) — the script and its fixture-based tests are still here for reference.pdf-template.py— Data-driven ReportLab engine for role-specific learning-plan PDFs. Reads a role config fromroles/<slug>.json(seeroles/_example.jsonfor the schema) and writes the PDF to the path declared inoutput. Run withpython pdf-template.py roles/<slug>.json.
Notes
This is a public snapshot exported from a private working repo — real personal data was replaced before publishing:
Resume_Snapshot.mdhere is a fictional example persona (see the note at the top of this file), andapp-engine-bundle.md(real PII when generated) stays gitignored exactly as in the private repo.outputs/directories in each project are working dirs (regenerated artifacts) and are gitignored at the repo root.venv:
.venv/is gitignored at both the repo root and project-2 level (belt-and-suspenders).
Changelog
v0.2.0
Strict alias validation in
shared/fit_engine.py—_load_aliases()now raisesValueErroron malformed alias entries (non-list, non-string items, missing keys) instead of iterating single-character strings silently and silently scoring everything as a match. Malformedaliases.jsonwill now fail loudly at fit-check time.Expanded JD parser section-end regex (
shared/jd_parser.py) — adds "What we offer", "Benefits", "Perks", "Compensation", "Why join/work", "About us/the company", "Our culture", and "Company overview" as section-reset headings so the requirements parser stops picking up boilerplate as required skills.pre-commitalready includescheck_bundle_freshness.py+outputs/profile-bundle.jsongate (this was a no-op migration — public was already ahead of private on this front).New
tests/test_cli_common.py(5 tests) +_cli_common.pyextended withload_bundle_or_none(),print_wrote(),run_and_report()helpers from the private repo.New
shared/copy_fragments.pyandshared/cert_status.py— extraction of cert-status and copy-fragment computation fromrender_md_bundles.pyinto shared helpers, so future generators (LinkedIn / Jobgether / Job Board / Pluralsight profile drafts) can call them directly from a loaded bundle without re-parsing the rendered markdown.render_md_bundles.pyis wired to the new modules;tests/test_render_md_bundles.pyupdated to test the public-API surface.
v0.1.0
Initial public release.
This server cannot be deployed
Maintenance
Related MCP Connectors
Generate tailored, ATS-optimized resume PDFs and cover letters from a job description, over MCP.
Build an ATS-friendly resume and check it against a job description, fully offline.
Analyze job listings against your resume, track applications, and generate cover letters.
Tailored, graded job applications: a CV, cover letter and form answers built per vacancy.
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceEnables Claude Desktop to manage a job search end-to-end: find and score job listings, tailor resumes, generate application messages, and track application history, while leaving final external actions to the user.-
- AlicenseAqualityBmaintenanceEnables parsing a master resume, analyzing job descriptions for ATS/match scores, generating truthful tailored resumes, tracking applications, and producing PDF reports through Claude Desktop.17MIT
- AlicenseAqualityBmaintenanceEnables LLM clients to analyse job postings, tailor resumes from an evidence-labelled profile, validate every claim against that profile, and track applications, all through deterministic MCP tools.7Apache 2.0
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to tailor a resume to any job description by extracting keywords, analyzing gaps and ATS compliance, managing versions, and compiling PDF/LaTeX outputs entirely locally without external API keys.MIT