Metadata-Version: 2.4
Name: stellenpilot
Version: 0.7.1
Summary: Local job search assistant for Germany: finds jobs daily, scores them against your CV, and writes truthful tailored CVs and cover letters.
Author: Sourav Sarker
License-Expression: MIT
Project-URL: Homepage, https://github.com/srvskr1/stellenpilot
Project-URL: Issues, https://github.com/srvskr1/stellenpilot/issues
Project-URL: Documentation, https://github.com/srvskr1/stellenpilot/blob/main/INSTALL.md
Keywords: job search,cv,resume,germany,werkstudent,llm,ollama
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: python-docx>=1.1
Requires-Dist: pypdf>=6.19
Provides-Extra: gmail
Requires-Dist: google-api-python-client>=2.100; extra == "gmail"
Requires-Dist: google-auth-oauthlib>=1.2; extra == "gmail"
Dynamic: license-file

# Stellenpilot

**Your local AI job assistant. Open source, private, and on autopilot.**

[![PyPI](https://img.shields.io/pypi/v/stellenpilot)](https://pypi.org/project/stellenpilot/)
[![Python](https://img.shields.io/pypi/pyversions/stellenpilot)](https://pypi.org/project/stellenpilot/)
[![tests](https://github.com/srvskr1/stellenpilot/actions/workflows/tests.yml/badge.svg)](https://github.com/srvskr1/stellenpilot/actions/workflows/tests.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/srvskr1/stellenpilot/blob/main/LICENSE)

Stellenpilot is an AI agent for your job search that runs on your own computer. Every morning it finds new jobs, an AI reads each one against your CV, tells you honestly how well it fits, and writes a tailored CV and cover letter for the best matches. When you open the dashboard, the work is done: you read, decide and send.

It comes with its own **free built-in AI**, so you need no account, no API key and no cloud. Your CV never leaves your computer. Built for the job market in Germany, and it works in other countries too.

![Stellenpilot in about a minute: the four setup steps, Home, the agent office, Jobs, Applications and Settings](https://raw.githubusercontent.com/srvskr1/stellenpilot/main/docs/demo.gif)

<sub>All names, companies and jobs in this demo are fictional.</sub>

**Windows:** [download the app](https://github.com/srvskr1/stellenpilot/releases/latest), no Python needed. **Everyone else:**

```bash
pip install stellenpilot
stellenpilot serve
```

Your browser opens Stellenpilot by itself. Setup takes a few minutes, plus the one time AI download: drop your CV, say what you are looking for, press **Download** for the built-in AI, and switch on the daily search. It also puts a **Stellenpilot icon on your desktop**: from then on you just double click it, no commands. Windows, macOS and Linux, Python 3.11 or newer.

## How it works

```mermaid
flowchart LR
    A["🔎 Collect<br/>6 job sources<br/>+ 200 company sites"] --> B["🧠 AI scores<br/>each job 0 to 100<br/>with reasons and gaps"]
    B --> C["✍️ AI writes<br/>tailored CV and<br/>cover letter"]
    C --> D["📬 Gmail tracks<br/>replies and moves<br/>statuses forward"]
    D --> E["✅ You decide<br/>read, edit, send"]
```

Every day, by itself:

1. **Collect.** Stellenpilot searches the Bundesagentur für Arbeit, Arbeitnow, Adzuna, TheirStack, Jobicy and Remotive, plus the career pages of about 200 companies with offices in Germany. Duplicates are removed.
2. **Score.** The AI reads each ad against your CV and gives a match from 0 to 100, a short reason, and the honest gaps. It reads which German level the ad really asks for and skips ads far above yours.
3. **Write.** For the best matches it writes a CV and a cover letter tailored to that job, using only facts from your CV, as Word files and PDF.
4. **Track.** With Gmail connected, confirmations, interview invitations and rejections move each application forward on their own. Interviews get a prep pack.
5. **Report.** The dashboard (and, if you like, a Telegram or email digest) shows what is ready to send today.

**It never applies for you and never contacts a company.** The agent prepares; you stay in control of every application.

## The AI

### What the AI does for you

* **Reads your CV.** Drop a PDF or Word file and the AI turns it into a structured profile. Every bullet is checked against your original, and anything left out or made up is flagged.
* **Scores every job** from 0 to 100 with a one line reason and the honest gaps (for example "asks for dbt, which you are still learning").
* **Understands German job ads.** It finds the German level an ad really needs (A1 to C2, from phrases like "verhandlungssicher" or "gute Deutschkenntnisse"), compares it with yours, and writes an English summary of every German ad.
* **Tailors your CV.** It picks and orders the experience, projects and skills from your profile that matter most for this job, and chooses the best fitting headline.
* **Writes the cover letter** in natural language for that company and role, plus a short report: what the ad asks for, what you cover, and which gaps to be honest about. German letters only if your German is B2 or better.
* **Prepares interviews** with likely questions and questions to ask them.
* **Learns your taste.** Mark jobs as a good match or not for you, and the next search leans toward what you liked.

### Truthful by design

A job assistant that invents experience gets people into trouble. Stellenpilot has a **truth guard**: any generated sentence that mentions a number, a tool or a language level your profile does not back up is rejected and replaced with safe text. Skills in a group called "Learning" are never presented as experience. The AI rephrases and selects; it never adds facts.

### Choose your AI

| | Built-in AI | Ollama, LM Studio, llama.cpp | Claude or OpenAI | No AI |
|---|---|---|---|---|
| Setup | one **Download** button | install the app, pull a model | paste an API key | nothing |
| Cost | free | free | a few cents a day | free |
| Privacy | stays on your computer | stays on your computer | CV and ads go to the provider | stays on your computer |
| Writing | good | depends on the model | best | templates |
| Speed | slower (see below) | depends on your computer | fast | instant |

**Built-in AI** is the default for new users. Pick it in setup or in **Settings, AI model** and press **Download**. Stellenpilot downloads the [llama.cpp](https://github.com/ggml-org/llama.cpp) engine and an open Qwen3.5 model (Apache 2.0) once, into `~/.stellenpilot/ai`. It starts by itself when a search needs it and stops when the search is done.

| model | download | memory | writing |
|---|---|---|---|
| Standard: Qwen3.5 4B (default) | 2.7 GB | about 6 GB free | better |
| Light: Qwen3.5 2B | 1.3 GB | runs with 8 GB in total | simpler, about twice as fast |

**How fast is it?** It runs on your processor, so it is slower than Claude, but free and private:

* Standard on a typical laptop: about 20 to 40 seconds to score one job, and 1 to 2 minutes for a CV with its cover letter. Light is about twice as fast.
* To keep searches short, an AI on your own computer reads the 20 most promising new jobs of each search (picked by keywords); the others keep a keyword score. Change it with `max_ai_jobs` under `[llm]`.
* A daily search with the AI takes about 10 to 20 minutes with Standard, or 5 to 10 with Light, in the background. Without AI it takes a minute or two.
* Measured on our small test server with only 2 processor cores: Standard needed 67 seconds per job and 2 minutes per CV and letter; Light 32 seconds and about 1 minute. Older laptops can be that slow; newer ones and Macs with Apple chips are faster.
* After the download, **Test speed** in Settings measures your own computer.

The laptop figures are estimates from published CPU benchmarks for these model sizes, not measured on every computer.

<details>
<summary><b>Using your own local model or a cloud API</b></summary>

Set `[llm]` in `config.toml`, or choose it in **Settings, AI model**:

| provider | what you need | notes |
|---|---|---|
| `builtin` | press Download once in Settings | Local and free, set up by Stellenpilot. `model = "standard"` or `"light"`. |
| `ollama` | Ollama running, a pulled model | Local and free. |
| `lmstudio` | LM Studio with its server started | Local and free. |
| `llamacpp`, `vllm`, `local` | a running server | Any OpenAI compatible local server. |
| `anthropic` | `ANTHROPIC_API_KEY` in `.env` | Claude through the Anthropic API. |
| `openai` | `OPENAI_API_KEY` in `.env` | OpenAI API. |
| `none` | nothing | Keyword scoring and template letters. |

Which local model for Ollama or LM Studio? Pick an instruction tuned version, because the tool asks for JSON answers.

| your computer | try | download |
|---|---|---|
| 8 GB RAM, no GPU | `ministral-3:3b` or `qwen3.5:2b`. Expect rougher scores and shorter letters. | about 3 GB |
| 16 GB RAM, or a GPU with 8 GB | `qwen3.5:4b` (default pick), or `ministral-3:8b` if many of your ads are in German | 4 to 6 GB |
| GPU with 16 GB or more | `qwen3.5:9b` or `gemma4:12b` | 7 to 9 GB |

Why these (checked on their model cards, October 2026): all are Apache 2.0, run in Ollama, and handle JSON well. Qwen3.5 covers 201 languages; Ministral 3 lists German among its main languages and is built for JSON output; Gemma 4 is Google's newest small family. Qwen3.5 and Gemma 4 can "think" before answering, which makes them slow; Stellenpilot switches that off for Ollama (set `think = true` under `[llm]` to turn it back on).

What we saw in testing with a very small model (Qwen2.5 1.5B on 2 CPU cores): the pipeline worked end to end, the German check and the truth guard did their job, and the cover letter stayed truthful. But the model gave every job the same score and wrote a two sentence letter, and each answer took about a minute. Small models are fine for trying the setup, not for real use.

Full setup for Ollama, LM Studio, llama.cpp, vLLM and Docker, plus speed tips and troubleshooting: [docs/local-llm.md](https://github.com/srvskr1/stellenpilot/blob/main/docs/local-llm.md). Run `stellenpilot doctor` to check that your model server is reachable and the model is installed.

</details>

## Automation

* **Daily autopilot.** Switch on **Automatic search** in Settings and pick a time. Stellenpilot sets up Task Scheduler on Windows or cron on macOS and Linux for you. The dashboard does not need to be open. A search missed because the computer was off runs when you log in or open Stellenpilot. Doing it by hand: [docs/scheduling.md](https://github.com/srvskr1/stellenpilot/blob/main/docs/scheduling.md).
* **Company watchlist.** Switch on the ready made list of about 200 companies with offices in Germany, or add your dream companies that use Greenhouse, Lever, Ashby, Personio or SmartRecruiters. Their new roles often appear here before they reach the job boards.
* **Gmail sync.** Read only. Connect it in **Settings, Gmail** in three steps, and statuses move forward as replies arrive. It never sends, deletes or labels mail. Details: [docs/gmail.md](https://github.com/srvskr1/stellenpilot/blob/main/docs/gmail.md).
* **Daily digest** to Telegram or email: top new matches, documents ready to send, interviews. See [docs/digest.md](https://github.com/srvskr1/stellenpilot/blob/main/docs/digest.md).
* **Jobs you found yourself.** Paste a link or the ad text from LinkedIn, a friend or anywhere, and the AI scores and tailors it like the rest.

## The dashboard

Five calm pages, in your browser, on your computer:

* **Home**: what is ready to apply, interviews coming up, the newest matches, and a small 3D office where you can watch the agent work.
* **Jobs**: every job with its score, why it fits, honest gaps, your documents, notes and interview prep.
* **Applications**: a board you drag cards across (Applied, Interview, Offer, Rejected), with reply rates by source, the skill gaps employers mention most, and a weekly summary.
* **My CV**: your profile, with tips to improve your matches.
* **Settings**: job sources, the AI, the daily search and Gmail, with step by step help for every key.

## Install

### Windows: download the app (easiest)

**[Download Stellenpilot for Windows](https://github.com/srvskr1/stellenpilot/releases/latest)** (the file `Stellenpilot-Setup-X.Y.Z.exe`, about 26 MB). Python is included, nothing else to install. Run it, then double click **Stellenpilot** on your desktop.

Windows may say "Windows protected your PC" because the app is not code signed yet. Click **More info**, then **Run anyway**. The installer is built by GitHub straight from this repository.

### With Python (Windows, macOS, Linux)

**New to Python or the terminal?** Follow [INSTALL.md](https://github.com/srvskr1/stellenpilot/blob/main/INSTALL.md): step by step for Windows, macOS, Linux and Docker, from installing Python to your first search.

```bash
pip install stellenpilot
mkdir my-hunt
cd my-hunt
stellenpilot serve      # the browser opens by itself, and so does setup
```

**Starting it again later:** double click the **Stellenpilot** icon on your desktop. Setup offers to create it; you can also do it under **Settings, Desktop icon** or with `stellenpilot shortcut`. Keep the small window it opens running while you use Stellenpilot, and close it when you are done. The daily search does not need it.

**"stellenpilot is not recognized"?** pip put the command in a folder that is not on your PATH. Use `python -m stellenpilot serve` instead (`python3` on macOS and Linux). That always works.

Update with `pip install -U stellenpilot`. Your files in `my-hunt` are never touched by an update.

<details>
<summary><b>From source, or with Docker</b></summary>

**From the source code** instead: you need Python 3.11 or newer (or Docker, see below). Works on Windows, macOS and Linux. On Debian or Ubuntu also install `python3-venv`. On Windows use `python` where the commands below say `python`; on macOS and Linux it may be `python3`.

```bash
git clone https://github.com/srvskr1/stellenpilot.git
cd stellenpilot
python -m venv .venv
# Windows: .venv\Scripts\activate    macOS or Linux: source .venv/bin/activate
pip install -e .

mkdir my-hunt
cd my-hunt
stellenpilot init      # creates config.toml, profile.toml and .env
stellenpilot demo      # optional: fictional sample jobs, to look around first
stellenpilot serve     # open http://127.0.0.1:8765
```

Prefer Docker? No Python needed:

```bash
mkdir data
docker compose build
docker compose run --rm stellenpilot init
docker compose up -d      # http://127.0.0.1:8765
```

See [docs/docker.md](https://github.com/srvskr1/stellenpilot/blob/main/docs/docker.md) for daily runs and details.

</details>

Prefer files to the dashboard? Everything also lives in `profile.toml`, `config.toml` and `.env`, `stellenpilot run` searches from the terminal, and `stellenpilot doctor` checks the setup.

## Job sources

| source | key | cost and limits | terms you should know |
|---|---|---|---|
| Bundesagentur für Arbeit | none | free | Community documented endpoint (jobsuche.api.bund.dev). No published limits, so requests are kept small. |
| Arbeitnow | none | free | Their terms require a link back to arbeitnow.com. The dashboard shows it. |
| Adzuna | free, from developer.adzuna.com | default 250 calls a day | Allowed for personal research. Adzuna must be credited; every Adzuna job links to Adzuna. Returns short snippets, not full ads. |
| TheirStack | free, from theirstack.com | 200 credits a month, 1 credit per job | Keys may not be shared. Each user needs their own. |
| Jobicy | none | free, one pass an hour at most | Remote jobs only. Credit Jobicy with a link to the listing; the dashboard does this. |
| Remotive | none | free, about 4 calls a day at most | Remote jobs only, one call per run. Small feed, delayed by a day. Credit and link back to Remotive; the dashboard does this. |

There is no LinkedIn, StepStone or Indeed scraper on purpose. LinkedIn's and StepStone's terms forbid scraping, and Indeed has no public job search API. See [docs/sources.md](https://github.com/srvskr1/stellenpilot/blob/main/docs/sources.md) for the details and links.

Other countries: set `country` in `config.toml`. Adzuna covers 19 countries, Jobicy and Remotive cover remote roles open to your country, TheirStack and the company watchlist cover any country, and the Bundesagentur and Arbeitnow cover Germany only.

## Privacy and safety

* **Local first.** Everything is stored in `jobhunt.db` and the `output` folder next to your config, on your computer. With the built-in AI or another local model, nothing about you leaves it.
* With Claude or OpenAI, your profile and the job ads are sent to that provider.
* The dashboard listens on 127.0.0.1 only, and write requests need a custom header, so other websites cannot change your data through your browser.
* Read every document before you send it. The truth guard checks digits and the tools it knows (see `VOCAB` in `stellenpilot/score.py`). It cannot judge spelled out numbers or vague claims, so you are the final check.

## Commands

| command | does |
|---|---|
| `stellenpilot init` | create config, profile and .env from the examples |
| `stellenpilot doctor` | check the setup and keys |
| `stellenpilot run` | search, score, tailor, and sync Gmail if enabled |
| `stellenpilot run --no-tailor` | search and score only |
| `stellenpilot serve` | start the dashboard on 127.0.0.1:8765 and open it in the browser (`--no-browser` to skip) |
| `stellenpilot shortcut` | put a Stellenpilot icon on the desktop that starts this workspace |
| `stellenpilot gmail` | sync statuses from Gmail once |
| `stellenpilot demo` | load fictional sample jobs |
| `stellenpilot import cv.pdf` | turn your CV into `profile.imported.toml` to review |
| `stellenpilot add LINK` | add a job from a careers page link |
| `stellenpilot add --text ad.txt --title "..." --company "..." --tailor` | add a pasted ad and tailor it now |
| `stellenpilot watch LINK` | find the watchlist entry for a company |
| `stellenpilot notify-test` | send a test digest |
| `stellenpilot telegram-id` | show your Telegram chat id |

Use `--home PATH` to keep your files in another folder.

## Project layout

```
stellenpilot/
  sources/      one module per job API
  pipeline.py   the daily run: collect, score, tailor, Gmail
  score.py      LLM or keyword scoring, taste from your ratings
  tailor.py     truthful CV plan, DOCX, cover letter, report, PDF
  server.py     local dashboard API
  web/          dashboard page
  examples/     example config and profile
tests/          offline tests: python -m unittest discover -s tests
```

## Uninstall completely

Do these steps in order. Steps 1 and 2 matter most: they stop the daily search before the program is gone.

**1. Stop the dashboard.** Press **Ctrl+C** in the terminal where `stellenpilot serve` runs (Docker: `docker compose down`).

**2. Remove the automatic daily search**, if you switched it on. Easiest: in the dashboard open **Settings**, switch off **Search every day** under Automatic search and press **Save changes**. If the dashboard is already gone:

* Windows (PowerShell): `schtasks /Delete /TN "Stellenpilot daily search" /F`
* macOS and Linux: run `crontab -e` and delete the line that ends with `# jobhunt-daily`

**3. Remove the program.**

* Windows app: Windows Settings, Apps, Stellenpilot, Uninstall. It also removes the daily search task. Your files in `Documents\Stellenpilot` stay; delete that folder too if you want everything gone.
* Installed with pip: activate the environment you installed it in, then `pip uninstall stellenpilot`. Delete that environment folder too if you made one just for it (for example `stellenpilot-env` or `.venv`).
* Installed from source: delete the `stellenpilot` folder you cloned or unzipped (the environment `.venv` is inside it).
* Docker: in the project folder run `docker compose down`, then `docker rmi ghcr.io/srvskr1/stellenpilot` (and `docker image prune` to free the space of any self built image).

**4. Delete your data.** Your workspace folder (`my-hunt`, or `data` for Docker) holds everything personal: your CV profile, `.env` with your API keys, the job database, the generated CVs and cover letters, `run.log`, backups and the Gmail `token.json`. Delete the whole folder. The only other place is the Built-in AI folder `.stellenpilot` in your home folder, if you downloaded it (see step 5).

**5. Close your accounts and keys** (optional, but good practice):

* API keys you created for it: delete them at Adzuna, TheirStack, Anthropic or OpenAI.
* Gmail sync: remove access at https://myaccount.google.com/permissions and delete the Google Cloud project you made for it.
* Telegram digest: send `/deletebot` to @BotFather.
* Built-in AI: press **Remove the AI files** in Settings, or delete the folder `.stellenpilot` in your home folder (`C:\Users\<you>\.stellenpilot` on Windows). It holds the engine and the model, about 1.5 to 4 GB.
* Ollama model: `ollama rm qwen3.5:4b` (or the model you pulled), and uninstall Ollama or LM Studio if you only used them for this.

LibreOffice and Python stay installed; remove them like any other app if you no longer need them.

## Contributing

Issues and pull requests are welcome. New sources should use an official or clearly permitted API, follow the shape in `stellenpilot/sources/__init__.py`, and come with an offline test.

## Credits and license

MIT, see [LICENSE](https://github.com/srvskr1/stellenpilot/blob/main/LICENSE). Credits for ideas and data are in [NOTICE.md](https://github.com/srvskr1/stellenpilot/blob/main/NOTICE.md). The built-in AI uses [llama.cpp](https://github.com/ggml-org/llama.cpp) (MIT) and [Qwen3.5](https://huggingface.co/Qwen) models (Apache 2.0), downloaded from their official sources.
