A self-hosted Telegram bot that evaluates job descriptions against your resume using a local LLM. Paste a job description or send a link, get a match score, a breakdown of where you fit and where you don't, and an honest explanation — all from your phone.
Built with n8n, Ollama, and Telegram. No cloud AI APIs required. Everything runs on your own machine.
| Command | What happens |
|---|---|
/resume |
Upload your resume as a PDF. The bot extracts your skills and saves your profile. |
/jd |
Start a job description check. Paste the JD over one or more messages, then send /done. Or send /jd https://... to process a link directly. |
/done |
Process the accumulated job description and return your match results. |
/skills |
View skills extracted from your resume, or add skills the bot missed. |
/clarify |
Correct experience assumptions (e.g. /clarify 4 years React, 2 years Node.js). |
/whoami |
Get a career summary of who you are based on your resume. |
/status |
View everything currently stored — resume, skills, clarifications. |
/reset |
Clear stored data. Options: skills, clarify, resume, all. |
Example output for a /done check:
🟡 Apply with Caution — 63/100
🧠 Breakdown:
• Skills: 22/35
• Experience: 25/25
• Tech: 11/15
• Domain: 5/10
⚠️ Missing Skills:
Kubernetes, CI/CD pipelines
💬 Your backend experience maps well to this role and you meet
the years requirement comfortably. The main gaps are around
deployment infrastructure — Kubernetes and CI/CD are listed as
required and aren't evidenced in your profile.
Before you start, make sure you have the following installed:
- n8n — version 2.0 or higher recommended. This workflow was built on v2.15.
- Ollama — to run the local LLM
- A Telegram account — to create the bot
- A way to expose your local n8n to the internet — Cloudflare Tunnel is recommended and free
- Open Telegram and search for @BotFather
- Send
/newbot - Give it a name (e.g.
Matchra) - Give it a username — must end in
bot(e.g.matchra_bot) - BotFather replies with your bot token — it looks like
123456789:AAGXi0y4... - Save this token — you will need it in Step 4 and Step 5
Then register the commands so they appear as autocomplete in the chat:
- Send
/mybotsto BotFather - Select your bot
- Tap Edit Bot → Edit Commands
- Paste the following exactly:
resume - Save your resume (attach PDF)
jd - Start a job description check
done - Process the pasted job description
skills - View or add skills
clarify - Fix experience assumptions
whoami - Get a summary of who you are
status - View your current profile
reset - Clear stored data
Ollama lets you run LLMs locally. Download it from ollama.com for your OS (Mac, Windows, Linux all supported).
Once installed, start it by running:
ollama serveOllama runs on http://localhost:11434 by default. This is the endpoint Matchra uses — no changes needed.
Matchra requires a model capable of following structured JSON instructions reliably. You need to pull at least one model before the workflow will function.
Model recommendations by hardware:
| Your hardware | Recommended model | Pull command |
|---|---|---|
| 16GB+ RAM, modern GPU | gemma4:e4b (used to build this) |
ollama pull gemma4:e4b |
| 16GB RAM, no GPU | llama3.2:3b |
ollama pull llama3.2:3b |
| 8GB RAM | llama3.2:1b |
ollama pull llama3.2:1b |
| 8GB RAM (alternative) | phi3:mini |
ollama pull phi3:mini |
| Low spec / older machine | tinyllama |
ollama pull tinyllama |
Note on model quality: Smaller models will work but produce lower quality reasoning and may occasionally return malformed JSON.
llama3.2:3bis the recommended minimum for good results.gemma4:e4bwas used to develop and test this workflow — it produces the best output but requires a beefy machine.
Once pulled, verify it works:
ollama run llama3.2:3b "Say hello"If you don't have n8n installed:
npm install -g n8nThen start it:
n8n startn8n runs on http://localhost:5678 by default. Open that in your browser to access the editor.
n8n requires Node.js 18 or higher. Check with
node --version.
Telegram needs to reach your n8n instance to deliver messages. Since n8n runs locally, you need a tunnel.
Cloudflare Tunnel (recommended — free)
- Install
cloudflaredfrom developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads - Run a quick tunnel (no account needed for testing):
cloudflared tunnel --url http://localhost:5678- Cloudflare gives you a public URL like
https://something-random.trycloudflare.com - Keep this running — n8n must be reachable at this URL for the bot to work
For a permanent setup with a custom domain, follow Cloudflare's named tunnel documentation. The random URL changes every time you restart the tunnel.
- Open n8n at
http://localhost:5678 - Click the menu (top left) → Import from File
- Select
Matchra_v1.jsonfrom this repository - The workflow imports with 57 nodes
When you import the workflow, all Telegram reply nodes will show a credential error. You need to connect your bot token once and it applies everywhere.
- Click any Telegram node that shows an error (e.g. Telegram Trigger)
- Click the credential dropdown → Create New Credential
- Paste your bot token from Step 1
- Click Save
All other Telegram nodes in the workflow use the same credential — they will automatically resolve once you save it.
Two nodes make direct calls to the Telegram file API using a URL that includes the bot token. These need to be updated manually after import.
Open each of the following nodes and replace YOUR_TELEGRAM_BOT_TOKEN in the URL field with your actual bot token:
Node 1 — Retrieve File ID from Telegram
URL field currently reads:
https://api.telegram.org/botYOUR_TELEGRAM_BOT_TOKEN/getFile?file_id={{ $json.fileId }}
Replace with:
https://api.telegram.org/bot123456789:YOUR_ACTUAL_TOKEN/getFile?file_id={{ $json.fileId }}
Node 2 — Retrieve File From FileID
URL field currently reads:
https://api.telegram.org/file/botYOUR_TELEGRAM_BOT_TOKEN/{{ $json.result.file_path }}
Replace with:
https://api.telegram.org/file/bot123456789:YOUR_ACTUAL_TOKEN/{{ $json.result.file_path }}
The workflow uses gemma4:e4b across all four LLM nodes. If you pulled a different model in Step 2, update the model name in these four nodes:
Connect to LLMConnect to LLM1Extract InformationResume Keyword Extractor
In each node, find the JSON Body field and change "model": "gemma4:e4b" to match the model you pulled. For example:
{
"model": "YOUR_OLLAMA_MODEL",
"stream": false,
"prompt": {{ JSON.stringify($json.prompt) }}
}All four nodes must use the same model name.
- Click Save in the top right of the workflow editor
- Toggle the workflow from Inactive to Active using the toggle in the top right
The workflow is now live. Any message sent to your Telegram bot will be processed.
Send your bot the following in order:
- Attach your resume PDF and send it with
/resumeas the caption - Wait for the "Resume saved" confirmation — it will also show a list of extracted skills
- Send
/statusto confirm your profile is stored correctly - Send
/jd— the bot will prompt you to paste a job description - Paste a job description (can be multiple messages if it's long)
- Send
/done - You should receive your match score, breakdown, missing skills, and reasoning
Bot doesn't respond to messages
- Check that your Cloudflare tunnel is running and n8n is accessible at the public URL
- Make sure the workflow is set to Active in n8n
- Open the n8n executions log (left sidebar) to see if the trigger is firing
"Resume saved" but skills list is empty
- Your resume may be a scanned image PDF rather than a text-based PDF. The Extract from File node cannot read scanned documents. Export your resume from Word or Google Docs as a PDF to ensure it contains selectable text.
Score seems wrong or missing skills are skills you have
- Use
/skillsto see what was extracted from your resume - Use
/clarifyto correct experience years if the LLM estimated incorrectly - Use
/skills Docker, AWSto manually add skills the extraction missed - Smaller models are less accurate at normalization — consider upgrading to a larger model if results are consistently off
LLM returns malformed JSON
- This happens occasionally with smaller models. Send
/doneagain to retry. - If it happens frequently, switch to a larger model (see Step 2 recommendations)
llama3.2:3bor higher is recommended for reliable JSON output
/jd with a link fails or returns empty content
- Many job boards (LinkedIn, Indeed) block automated requests. For these sites, copy and paste the job description text directly instead of sending the link.
- Company career pages and ATS-hosted listings (Greenhouse, Lever, Workable) generally work fine with links.
n8n says "could not connect to Ollama"
- Make sure Ollama is running:
ollama serve - Confirm it's accessible:
curl http://localhost:11434 - Both n8n and Ollama must be running at the same time for the workflow to function
Matchra uses a deterministic scoring engine rather than asking the LLM to assign scores directly. This keeps results consistent — the same resume against the same JD always produces the same score regardless of LLM temperature or variation.
The LLM is used for two things only: structured data extraction (parsing resume and JD into comparable fields) and natural language reasoning (explaining what the score means in plain language).
Score breakdown:
| Category | Max points | How it's calculated |
|---|---|---|
| Skills match | 35 | Required JD skills found in your profile ÷ total required skills |
| Experience | 25 | Your years of experience ÷ years required (capped at 1.0) |
| Tech stack | 15 | JD tech stack items found in your profile ÷ total JD tech items |
| Domain fit | 10 | Full points if domains match, partial if adjacent, minimum if unrelated |
| Soft skills / culture fit | 15 | Overlap between soft signals in the JD (leadership, agile, communication, etc.) and your profile — optional skill matches contribute up to 5 bonus points here |
| Total | 100 |
Decision thresholds:
| Score | Decision |
|---|---|
| 75 and above | ✅ APPLY |
| 60 – 74 | 🟡 APPLY WITH CAUTION |
| Below 60 | 🔴 SKIP |
All data stays on your machine. Your resume, skills, and job descriptions are stored in n8n's local static data — nothing is sent to any external service. The only outbound calls are to your local Ollama instance and to the Telegram API (to send and receive messages from your bot).
No analytics, no logging to external services, no data retention outside your local n8n instance.
matchra/
├── n8n
├──Matchra_v1.json — n8n workflow (import this)
├── README.md — this file
└── .gitignore — excludes .env and any local config
- n8n — workflow automation
- Ollama — local LLM runtime
- Telegram Bot API — messaging interface
- Cloudflare Tunnel — local-to-public tunnel
Last Updated: April 13 2026