---
name: it-stellensuche
description: Search the web for NEW jobs matching the user's own search profile (cities / remote mode, taken from the Bewerbungs-Tracker) that they have NOT applied to yet, then present them and optionally import them as JobOffers into the Bewerbungs-Tracker. Use whenever the user wants to find new job postings, "Stellensuche", "neue Stellen suchen", "Jobs finden", "Systemadministrator-Stellen", or refresh open job leads. Deduplicates against existing Bewerbungen and Jobangebote via the bewerbungs-tracker skill.
---

# Stellensuche (Suchprofil des jeweiligen Benutzers)

Findet **neue** Stellen im Web — **in den Städten bzw. im Modus, die das Suchprofil des
Benutzers vorgibt** —, filtert alle raus, für die sich der Nutzer schon beworben hat
**oder die auf der Blacklist stehen**, und spielt sie auf Wunsch als JobOffers in den
Bewerbungs-Tracker ein.

> **Multi-User (WICHTIG):** Der Tracker ist eine Plattform mit mehreren Benutzern; jeder
> hat **sein eigenes Suchprofil und seinen eigenen API-Key**. Region, Modus und
> Ausschlüsse stehen **nicht mehr in diesem Skill**, sondern kommen von außen:
>
> 1. **Aus dem Prompt**, wenn er sie nennt (so ruft der Jobsuche-Runner den Skill auf —
>    er baut den Prompt aus dem Suchprofil des Benutzers). Der Prompt hat immer Vorrang.
> 2. **Sonst aus dem Tracker:** `GET /templates` (typ `Lebenslauf`) liefert Rolle und
>    Technologien des Benutzers; nach Orten/Modus fragen, wenn der Prompt nichts sagt.
>
> Die Beispiele weiter unten (Rollen, Buzzwords, Städte) sind **nur Muster** — niemals
> ungefragt die Städte oder das Profil eines anderen Benutzers verwenden. Der API-Key in
> `BEWERBUNG_API_KEY` bestimmt, in wessen Konto importiert wird.

> **Blacklist-Prinzip (zentral):** Jeder erfolgreich importierte Job wird
> **unmittelbar danach geblacklistet**. So taucht dieselbe Stelle in späteren
> Suchläufen nie wieder auf — die Dublett-Vermeidung bleibt bestehen, selbst wenn
> das JobOffer später gelöscht oder in eine Bewerbung überführt wird. Umgekehrt
> werden Kandidaten, die schon auf der Blacklist stehen, gar nicht erst gelistet
> oder importiert.

## Suchprofil

**Quelle des Profils (in dieser Reihenfolge):**

1. **Der Prompt** — der Jobsuche-Runner hängt den Lebenslauf/das Kurzprofil des Benutzers
   direkt an („--- PROFIL --- … --- ENDE PROFIL ---"). Rollen und Buzzwords **daraus**
   ableiten.
2. **Der Tracker** — sonst `GET /templates` (typ `Lebenslauf`, sonst `Profil/Kurzprofil`)
   des Benutzers, dem der `BEWERBUNG_API_KEY` gehört.
3. Erst wenn beides fehlt: aus den bereits erfassten Bewerbungen (`GET /applications`)
   ableiten oder nachfragen.

**Rolle:** breit fassen — dieselbe Tätigkeit läuft je nach Firma unter vielen Titeln.
Passende Bezeichnungen als Query-Varianten und für die Relevanzbewertung nutzen.

> Die folgende Liste ist ein **Beispiel für ein IT-Infrastruktur-Profil** — sie zeigt, wie
> breit zu fassen ist, ist aber **kein Default**. Für einen Benutzer mit anderem Beruf die
> Titel entsprechend aus **seinem** Lebenslauf bilden.

- **Kern (Beispiel: 2nd-Level-Sysadmin + IT-Consultant):**
  Systemadministrator, IT-Administrator, IT-Systemadministrator, IT-Systemadministration,
  IT-Systemadministrator 2nd Level, 2nd-Level-Administrator, System-Administrator (m/w/d),
  Fachinformatiker Systemintegration, Administrator (m/w/d).
- **Support/Betrieb:** 1st/2nd/3rd-Level-Support, 2nd-Level-Support, IT-Support,
  IT-Supporter, Support-Techniker, Helpdesk-Mitarbeiter, IT-Techniker,
  IT-Systemtechniker, Systemtechniker, IT-Systemelektroniker, Servicetechniker IT,
  Onsite-Techniker, Field-Service-Techniker, IT-Systembetreuer, IT-Betreuer,
  IT-Allrounder, IT-Koordinator, IT-Mitarbeiter, IT-Operations / IT-Betrieb,
  IT-Administrator EDV, EDV-Administrator, EDV-Betreuer.
- **Infrastruktur/Netz:** System Engineer, Systems Engineer, Infrastructure Engineer,
  IT-Infrastruktur, Infrastruktur-Administrator, Netzwerkadministrator, Network Engineer,
  Virtualisierungsadministrator, Storage-/Backup-Administrator, Rechenzentrums-Techniker,
  Datacenter-Techniker.
- **Cloud/Hosting/Modern Workplace (passt zu Hetzner/OVH im CV):** Cloud-Administrator,
  Cloud Engineer, Cloud-Operations-Engineer, Hosting-Administrator, Hosting Engineer,
  Microsoft-365-Administrator, M365-/Modern-Workplace-Administrator,
  Azure-/Entra-Administrator, DevOps-Engineer (Infrastruktur-lastig),
  Linux-Administrator, Linux System Engineer, Windows-Administrator.
- **Beratung/Leitung (klein) — deckt die CV-Rolle „IT-Consultant" ab:** IT-Consultant,
  IT-Berater (technisch, hands-on), IT-Systemberater, IT-Kundenberater (technisch),
  IT-Teamleiter/IT-Leiter in kleinen Firmen (nur wenn hands-on).

Ausschließen bleiben reine Softwareentwickler-, Data-Science-, Vertriebs- und
SAP-only-Stellen, außer sie passen klar zum Infrastruktur-Profil.

> **Ex-Arbeitgeber IMMER ausschließen (harte Regel, unabhängig von der Schreibweise):**
> Stellen der **„IT-Problemlöser"** (Essen) — voller Firmenname u. a.
> **„IT Problemlöser Verwaltungs- und Handels GmbH"**, auch **„IT-Problemlöser GmbH"**,
> **„IT Problemlöser"** o. Ä. — werden **nie** gelistet oder importiert. Es ist der
> frühere Arbeitgeber des Nutzers (siehe Lebenslauf). Diese Firma taucht immer wieder
> mit **wechselnden Stellentiteln** auf; die `firma_stelle`-Blacklist greift dann nicht,
> weil der Titel abweicht. Deshalb **jeden Treffer verwerfen, dessen Firmenname `IT
> Problemlöser` / `IT-Problemlöser` (in jeder Rechtsform-/Schreibvariante) enthält** —
> ohne auf die Blacklist zu warten. (Firmenweite `firma`-Blacklist-Einträge greifen
> inzwischen schreibweisen-robust über `firma_slug` inkl. Präfix-Match — diese
> Modell-Regel bleibt trotzdem als zusätzliche Sicherung bestehen.)

**Region: kommt aus dem Suchprofil des Benutzers, nicht aus diesem Skill.**

Der Prompt nennt entweder eine **Städteliste** (regionaler Modus) oder **100 % Remote /
deutschlandweit** — oder beides. Es gilt strikt:

- **Regionaler Modus:** **Nur** Stellen mit Arbeitsort in einer der **genannten** Städte.
  Die **erste genannte Stadt ist der Wohnort** und wird am höchsten priorisiert, danach
  in der angegebenen Reihenfolge. Orte **außerhalb** dieser Liste werden **verworfen** —
  auch das direkte Umland, und **auch reine Homeoffice-/Remote-Stellen ohne Sitz in einer
  der genannten Städte**. Sitzt der Arbeitgeber in einer der Städte und bietet zusätzlich
  Homeoffice, ist die Stelle zulässig.
- **Remote-Modus:** Nur Stellen, die **zu 100 % im Homeoffice** ausübbar sind
  (deutschlandweit, Firmensitz egal). Präsenz, Hybrid mit festen Bürotagen und vages
  „Homeoffice möglich" werden verworfen; die 100-%-Zusage live im Anzeigentext bestätigen.

Nennt der Prompt keine Region, **nachfragen** statt zu raten — niemals auf eine im Skill
hinterlegte Städteliste zurückfallen (die gibt es bewusst nicht mehr).

**Skills/Buzzwords** (für Query-Varianten & Relevanzbewertung): Die **Kernbegriffe kommen
aus dem Lebenslauf des jeweiligen Benutzers** (höchste Gewichtung); ergänze naheliegende,
dazu passende Technologien — als Suchbegriffe und zum Erkennen passender Anzeigen, auch
wenn sie nicht wörtlich im CV stehen.

> Auch die folgende Liste ist ein **Beispiel** (IT-Infrastruktur). Für andere Profile die
> Kernbegriffe aus **deren** Lebenslauf ziehen, nicht von hier.

- **Kern (Beispiel, aus einem Infrastruktur-CV):** Windows Server, Active Directory,
  Exchange, Microsoft 365 / MS365, Linux-Administration (Debian/Ubuntu),
  Docker/Container, Proxmox/Virtualisierung, Netzwerk (OPNsense, pfSense,
  VPN: WireGuard/OpenVPN/IPsec, LAN/WAN, TCP/IP), Firewall, Monitoring
  (Prometheus, Grafana, Beszel, Uptime Kuma), Hetzner/OVH Cloud, Self-Hosting,
  Automatisierung, AI/Claude/Agent-Workflows.
- **Microsoft-/Windows-Umfeld:** Entra ID / Azure AD, Intune, Endpoint Manager,
  Group Policy / GPO, WSUS, PowerShell, Hyper-V, SharePoint, Teams, Windows 10/11,
  Client-Management, MDM.
- **Virtualisierung/Server:** VMware vSphere / ESXi, Hyper-V, Citrix, KVM,
  Terminalserver / RDS, Server-Hardware (Dell/HPE/Lenovo).
- **Backup/Storage:** Veeam, Backup & Recovery, Datensicherung, NAS/SAN, TrueNAS,
  ZFS, Ceph, Synology, QNAP.
- **Netzwerk/Security:** VLAN, Routing & Switching, Cisco, Fortinet/FortiGate,
  Sophos, Ubiquiti/UniFi, DNS/DHCP, Reverse Proxy (Nginx, Traefik), Let's Encrypt,
  IT-Security, Patch-Management, ISO 27001, IT-Grundschutz.
- **Cloud/DevOps/Automatisierung:** Microsoft Azure, AWS, Kubernetes, Ansible,
  Terraform, GitLab / CI/CD, Bash-/Shell-Scripting, Portainer, Nextcloud.
- **Datenbanken/Web:** MySQL/MariaDB, PostgreSQL, MS SQL Server, Apache, Nginx, IIS.
- **Betrieb/Organisation:** Ticketsystem (Jira, OTRS, Zammad), Helpdesk,
  Rechenzentrum, On-Premise, Managed Services, IT-Dienstleister, Systemhaus.

> Aktuelles Profil (Titel, Skills, Ort) steht in der Lebenslauf-Vorlage der API:
> `bewerbungs-tracker` → `GET /templates` (typ `Lebenslauf`). Bei Bedarf dort
> gegenlesen, statt zu raten.

## Quellen-Politik (WICHTIG)

Ziel ist **immer die Original-Stellenausschreibung direkt beim echten Arbeitgeber**
— bevorzugt auf dessen **Firmen-/Karriereseite**.

- **Ausschließen (nicht listen, nicht importieren):**
  - **Headhunter / Personalvermittler / Personalberatungen** (recruiten für Dritte).
  - **Zeitarbeit / Arbeitnehmerüberlassung / Personaldienstleister** (z. B. Randstad,
    Hays, GULP, Amadeus FiRe, Adecco, Manpower, Piening, Tempton, DIS AG, Robert Half
    u. ä. — auch unbekannte, wenn die Anzeige „Arbeitnehmerüberlassung",
    „im Kundenauftrag", „für unseren Kunden", „Personaldienstleister" o. Ä. nennt).
  - **Stepstone** als Quelle — nicht als Board nutzen, keine `site:stepstone.de`-Query,
    keine Stepstone-Links importieren.
- **Erkennungsmerkmale eines Vermittlers/Zeitarbeit** (bei Unsicherheit die
  Firmen-/Impressumsseite per `WebFetch` prüfen): Formulierungen wie „für unseren
  Kunden", „im Auftrag unseres Mandanten", „Arbeitnehmerüberlassung", „Direktvermittlung",
  „Personaldienstleistung", „Recruiting-Partner"; oder die inserierende Firma ist erkennbar
  eine Personal-/Recruiting-Agentur. → **verwerfen**.
- **Zulässig als Quelle**, wenn es zur Original-Anzeige des Arbeitgebers führt:
  Firmen-Karriereseite (bevorzugt), Arbeitsagentur/Bundesagentur für Arbeit, Indeed
  oder LinkedIn **nur** wenn die Anzeige eindeutig vom echten Arbeitgeber (nicht von
  einem Vermittler) stammt. Führt ein Board-Treffer zu einer Firma, deren eigene
  Karriereseite dieselbe Stelle direkt listet, **immer den Firmen-Direktlink** nehmen.

## Workflow

1. **Bereits erfasste Jobs + Blacklist laden** (Dedup-Basis). Dieser Schritt ist
   **immer zuerst** auszuführen, damit Stellen aus früheren Suchläufen **nicht
   erneut** gefunden/importiert werden. Zwei Quellen:
   ```bash
   scripts/applied-set.sh      # firma_slug<TAB>firma<TAB>stelle<TAB>ort<TAB>quelle_url<TAB>external_id
   scripts/blacklist-set.sh    # id<TAB>typ<TAB>firma<TAB>stelle<TAB>ort<TAB>domain<TAB>url_norm<TAB>firma_norm<TAB>firma_slug<TAB>stelle_norm<TAB>ort_norm<TAB>grund
   ```
   - **applied-set** (Bewerbungen **und** importierte Jobangebote): **eine Zeile
     pro bereits erfasster Firma** (company-level, nicht mehr pro Stelle). Je Zeile
     drei Dublett-Merkmale merken: **`firma_slug`** (robuster Firmen-Schlüssel:
     lowercase, Umlaute→ae/oe/ue/ss, `(m/w/d)` raus, End-Rechtsform wie gmbh/ag/kg
     entfernt, mit `-` verbunden), **`quelle_url`** und **`external_id`**.
   - **blacklist-set** (gesperrte Muster): je Zeile den **`typ`** und die dazu
     passenden Felder merken (`url_norm`, `domain`, `firma_norm`, **`firma_slug`**,
     `stelle_norm`). Die `*_norm`/`firma_slug`-Felder liefert der Server bereits
     normalisiert (lowercase, Tracking-Parameter entfernt, `(m/w/d)`/Rechtsform
     bereinigt).

2. **Kandidaten sammeln — strukturierte Quelle zuerst, dann WebSearch.**

   **(a) Arbeitsagentur-API (primär — frisch, hohe Trefferzahl, strukturiert).** Vor
   der Freitext-Suche die Jobsuche-API der Bundesagentur für Arbeit abfragen. Sie
   liefert frische, deduplizierbare Treffer mit Firma, Ort, Datum und stabiler
   `refnr` — genau das, was reine WebSearch nicht zuverlässig hergibt. Pro Rolle einen
   Umkreis-Query:
   ```bash
   scripts/arbeitsagentur.sh search "<Rolle>" "<Stadt>" 15 30 50
   # -> firma_slug<TAB>firma<TAB>titel<TAB>ort<TAB>datum<TAB>refnr<TAB>angebotsart
   ```
   Rollen aus dem Suchprofil durchrotieren (Systemadministrator, IT-Administrator,
   Fachinformatiker Systemintegration, IT-Support, IT-Techniker, System Engineer,
   Netzwerkadministrator, …). Städte: **Gladbeck** deckt per Umkreis 15–20 km
   Bottrop/Gelsenkirchen/Essen/Oberhausen weitgehend mit ab; **Dorsten** und **Marl**
   je separat (`wo=Dorsten`, `wo=Marl`, Umkreis ~10). `tage` (Default 30) steuert die
   Frische. Achtung: der Umkreis zieht auch **Nachbarorte außerhalb der sieben
   Städte** rein (z. B. Haltern, Recklinghausen, Herten) — die **harte Regionsregel**
   (nur die sieben Städte, Schritt 3) über die `ort`-Spalte anwenden und Fremdorte
   **verwerfen**. Jede verbleibende Zeile **sofort per `firma_slug`** gegen
   applied-set/blacklist prüfen (Firmen-Dedup, Schritt 1) — bereits erfasste/gesperrte
   Firmen raus. Für
   **überlebende** Treffer die Details holen:
   ```bash
   scripts/arbeitsagentur.sh detail <refnr>
   ```
   Detail liefert **Volltext** (→ `beschreibung`), **`EXTERNE_URL`** (Original-Link des
   Arbeitgebers → bevorzugt `quelle_url`), **Adresse**, **Vergütung** und die Flags
   **`ZEITARBEIT_AUE` / `PRIVATE_ARBEITSVERMITTLUNG`** — steht dort `True`, ist es
   Zeitarbeit/Vermittler → **verwerfen** (ohne WebFetch, spart einen Schritt). Meldet
   das Detail „keine aktive Anzeige", ist sie abgelaufen → **verwerfen**. Die `refnr`
   ist stabil → als Existenz-Nachweis und für die `external_id` nutzbar. Führt
   `EXTERNE_URL` nur auf ein Board (nicht den Arbeitgeber), die Firmen-Karriereseite
   suchen und deren Direktlink bevorzugen (Quellen-Politik gilt unverändert).

   **(b) WebSearch (ergänzend — für alles, was nicht in der API steht).** Mit dem
   `WebSearch`-Tool **viele** Queries fahren — Rolle × Ort für **jede der sieben
   Städte**, mit Fokus auf **Original-Anzeigen der Arbeitgeber**. Nur diese sieben
   Orte abfragen, keine weiteren Revierstädte.

   > **Query-Strategie (Recall maximieren — WICHTIG, findet die Suche „kaum noch
   > Stellen"):** Lieber **viele einfache, natürlichsprachliche Einzel-Queries** als
   > wenige überladene. **Boolesche Operatoren sparsam einsetzen** — `OR`, `site:`,
   > `inurl:` und `-minus`-Ausschlüsse **senken bei WebSearch oft drastisch die
   > Trefferzahl**. Statt eine `A OR B OR C … -stepstone -zeitarbeit`-Monsterquery
   > lieber **getrennte, kurze Queries** absetzen und Vermittler/Stepstone erst
   > **nachträglich beim Filtern** (Schritt 3) rauswerfen. Pro Stadt **mehrere
   > Formulierungen** durchvariieren:
   > **Rolle × Ort × Suffix**, mit den Suffixen `Stellenangebot`, `Job`, `Jobs`,
   > `Stelle`, `Vollzeit`, `Festanstellung`, `unbefristet`, `gesucht`, `m/w/d`, `2026`
   > und **ganz ohne Suffix** (nur `Rolle Ort`). Zusätzlich **Buzzword × Ort**
   > (s. u.). So deckt jede Stadt 10–15 verschiedene Queries ab statt 1–2.

   **Rolle × Ort (je Stadt mehrere Suffixe durchspielen), Beispiele:**
   - `IT-Systemadministrator Gladbeck Stellenangebot`, `Systemadministrator Gladbeck`,
     `IT-Administrator Gladbeck Vollzeit`, `IT Systemadministrator Gladbeck m/w/d`
   - `Systemadministrator Essen Jobs`, `2nd Level Support Essen`,
     `IT-Administrator Essen Festanstellung`, `IT Systemadministrator Essen gesucht`
   - `Fachinformatiker Systemintegration Oberhausen`, `IT-Administrator Oberhausen Stelle`,
     `Systemadministrator Oberhausen unbefristet`
   - `IT Administrator Gelsenkirchen Stellenangebot`, `Systemadministrator Gelsenkirchen`,
     `IT-Systemadministrator Gelsenkirchen 2026`, `IT-Support Gelsenkirchen`
   - `Systemadministrator Bottrop Jobs`, `IT-Administrator Bottrop`,
     `IT Systemadministrator Bottrop Vollzeit`, `EDV-Administrator Bottrop`
   - `IT-Administrator Dorsten Stellenangebot`, `Systemadministrator Dorsten`,
     `IT-Techniker Dorsten Job`
   - `Systemadministrator Marl Stellenangebot`, `IT-Administrator Marl`,
     `IT Systemadministrator Marl Vollzeit`, `IT-Techniker Marl Job`
   - Weitere Titel je Stadt durchrotieren: `System Engineer <Ort>`,
     `IT-Systembetreuer <Ort>`, `Cloud Administrator <Ort>`, `Linux Administrator <Ort>`,
     `Netzwerkadministrator <Ort>`, `IT-Consultant <Ort>`, `IT-Support <Ort>`.
   - **Buzzword × Ort** (holt Anzeigen, die im Titel anders heißen, inhaltlich aber
     passen — s. Skills/Buzzwords oben): `Active Directory <Ort> Stellenangebot`,
     `Microsoft 365 Administrator <Ort>`, `VMware <Ort> IT Job`, `Proxmox <Ort>`,
     `Hyper-V Administrator <Ort>`, `Veeam <Ort> IT`, `PowerShell Administrator <Ort>`.
   - **Deutsche Jobbörsen zusätzlich anzapfen** (breitere Abdeckung, jeweils als
     eigene, einfache Query — nicht stapeln): `<Rolle> <Ort> meinestadt`,
     `<Rolle> <Ort> kimeta`, `<Rolle> <Ort> yourfirm`, `<Rolle> <Ort> arbeitsagentur`,
     `<Rolle> <Ort> indeed`. Falls doch ein `site:`-Filter, dann **einzeln**:
     `site:arbeitsagentur.de Systemadministrator <Ort>`, `site:de.indeed.com
     IT-Administrator <Ort>`, `site:de.linkedin.com/jobs Systemadministrator <Ort>`.
     **Kein** `site:stepstone.de`. Von Board-Treffern stets zur Original-Anzeige des
     Arbeitgebers durchklicken.
   - **Firmen-Karriereseiten gezielt** (bevorzugt): `IT-Administrator Essen Karriere`,
     `Systemadministrator Gelsenkirchen Karriere Stellenangebot`,
     `IT Jobs <Ort> Karriere` — Vermittler/Stepstone später beim Filtern aussortieren,
     nicht per `-minus` in der Query.

   Für Details/Ort/Firma einer Trefferseite `WebFetch` nutzen. Sieht ein Treffer nach
   Firmen-Karriereseite aus: dort direkt nach der Einzelanzeige suchen.

2b. **Firmen zuerst finden, dann deren Karriereseite prüfen** (Hauptquelle für
   „unentdeckte" Stellen). Board-Suchen finden nur, was breit ausgeschrieben ist —
   viele Arbeitgeber posten IT-Stellen **ausschließlich auf der eigenen Website**.
   Deshalb parallel zur Rolle-×-Ort-Suche **lokale Arbeitgeber in den sieben Städten
   identifizieren** und deren Karriereseite direkt öffnen:
   - **Arbeitgeber recherchieren** je Stadt — Firmen, die typischerweise interne IT
     oder IT-Dienstleistung haben: Systemhäuser/IT-Dienstleister, Industrie &
     Mittelstand, Chemie/Logistik (Essen, Oberhausen, Gelsenkirchen), Stadtwerke &
     kommunale Betriebe, Krankenhäuser/Kliniken, Hochschulen, Versicherungen/Banken,
     größere Handels-/Handwerksbetriebe. Beispiel-Queries:
     `größte Arbeitgeber Essen IT`, `Systemhaus Gelsenkirchen`,
     `IT-Dienstleister Oberhausen`, `Unternehmen Gladbeck IT-Abteilung`,
     `Stadtwerke Bottrop Karriere`, `Klinikum Dorsten Stellenangebote IT`,
     `Chemiepark Marl IT`, `Stadtwerke Marl Karriere`.
   - **Karriereseite direkt anfahren:** zu jeder gefundenen Firma
     `WebSearch "<Firma> Karriere"` bzw. `"<Firma> Stellenangebote"` und die
     Jobliste per `WebFetch` öffnen; auf offene **IT-/Administrator-/Support-Stellen**
     am jeweiligen Standort prüfen. Auch `inurl:karriere`, `inurl:jobs`,
     `inurl:stellen` gezielt einsetzen und gängige Bewerber-Portale erkennen
     (z. B. `/karriere`, `jobs.<firma>.de`, softgarden/onlyfy/Personio/Workday-Seiten).
   - **Buzzwords als Türöffner:** findet die reine Titel-Suche wenig, mit den
     Technologie-Buzzwords (oben) über die Stadt suchen, z. B.
     `VMware Essen Stellenangebot`, `Active Directory Gelsenkirchen Job`,
     `Microsoft 365 Administrator Oberhausen`, `Linux Bottrop IT` — so tauchen
     Anzeigen auf, die im Titel anders heißen, inhaltlich aber passen.
   - Jede so gefundene Stelle läuft durch dieselben Prüf-/Filter-/Dedup-Schritte
     (3–7). Der Firmen-Direktlink ist hier ohnehin schon die bevorzugte `quelle_url`.

3. **Filtern & bewerten:**
   - **Region (harter Ausschluss):** **nur** die sieben Städte Gladbeck, Essen,
     Gelsenkirchen, Oberhausen, Bottrop, Dorsten, Marl. Jede Stelle mit Arbeitsort außerhalb
     dieser sieben Städte **verwerfen** — auch übrige Revierstädte und reines
     Homeoffice/Remote ohne Sitz in einer der sieben Städte. **Nach Nähe zu Gladbeck
     priorisieren** (Gladbeck > Bottrop/Gelsenkirchen > Essen/Oberhausen > Dorsten/Marl).
   - **Rolle:** Systemadministration/IT-Infrastruktur; keine reinen Entwickler-,
     Vertriebs- oder SAP-only-Stellen (außer sie passen klar zum Profil).
   - **Quelle (harter Ausschluss):** Headhunter/Personalvermittler, Zeitarbeit/
     Arbeitnehmerüberlassung und Stepstone werden **verworfen** — siehe
     „Quellen-Politik". Nur Original-Anzeigen echter Arbeitgeber behalten.
   - **Dedup (persistent, FIRMEN-basiert):** **Eine Firma darf nur EINMAL gefunden
     werden.** Treffer **verwerfen**, sobald **eines** zutrifft: (a) gleiche/sehr
     ähnliche `quelle_url`, (b) gleiche `external_id`, oder (c) **die Firma steht
     schon im Applied-Set** — unabhängig vom Stellentitel. Firmen-Gleichheit über
     `firma_slug` prüfen: Kandidaten-Firma ebenso sluggen (lowercase, Umlaute→
     ae/oe/ue/ss, `(m/w/d)` & End-Rechtsform raus, mit `-` verbunden) und als
     **dieselbe Firma** werten, wenn der Slug **gleich** ist ODER **ein Slug ein
     führendes Bindestrich-Präfix des anderen** ist (mind. 2 Tokens) — so zählen
     **verschiedene Schreibweisen/Rechtsform-/Namensvarianten derselben Firma als
     eine** (z. B. „IT-Problemlöser GmbH" = „IT Problemlöser Verwaltungs- und Handels
     GmbH"; „Stadtwerke Essen" = „Stadtwerke Essen Netz GmbH"). Zusätzlich gesunder
     Menschenverstand: ist offensichtlich derselbe Arbeitgeber gemeint, als Dublette
     verwerfen. Distinkte Firmen mit nur gleichem ersten Wort (z. B. „Meyer IT" vs.
     „Meyer Logistik") sind **nicht** dieselbe Firma. So taucht kein Arbeitgeber aus
     früheren Läufen erneut auf. Im Zweifel behalten und als „evtl. Dublette" markieren.
   - **Blacklist (harter Ausschluss):** Kandidat **verwerfen** (nicht listen, nicht
     importieren), sobald er auf einen Blacklist-Eintrag passt — je nach `typ`:
     - `url` → normalisierte Kandidaten-URL == `url_norm`.
     - `domain` → Host der Kandidaten-URL == `domain` (auch Subdomains).
     - `firma` → **dieselbe Firma** wie der Eintrag (Kandidaten-`firma_slug` gleich
       `firma_slug` **oder** Präfix-Match wie bei der Dedup; `firma_norm` nur als
       Fallback für Alt-Einträge ohne Slug).
     - `firma_stelle` → dieselbe Firma (`firma_slug`, wie oben) **und** `stelle_norm`
       passen (ist `ort_norm` gesetzt, muss auch der Ort passen).
     - `auto` → wie die konkreten Felder, die der Eintrag trägt.
     Diese Muster sind bewusst blockiert (u. a. jeder früher importierte Job, siehe
     Schritt 6) — geblacklistete Stellen daher **stillschweigend überspringen**,
     nicht als „evtl. Dublette“ präsentieren.
   - **Relevanz:** höher gewichten, je mehr Buzzwords aus dem Profil passen.

4. **Existenz prüfen, Link prüfen, Kontakt-E-Mail & Firmenadresse recherchieren** —
   für jeden Treffer, der in die engere Wahl kommt, **zwingend einzeln**:
   - **Existenz-Prüfung (Pflicht):** Jede Stelle mit `WebFetch` auf dem Einzel-Link
     öffnen und bestätigen, dass die Anzeige **noch aktiv** ist (Firma + Stelle
     stehen dort, kein 404/„Stelle nicht mehr verfügbar"/Redirect auf Jobliste).
     Snippets aus der WebSearch reichen **nicht** — Suchindizes zeigen oft schon
     abgelaufene Anzeigen. Kein Live-Nachweis → Treffer **verwerfen** (nicht listen,
     nicht importieren). Bei bereits importierten Angeboten, die nicht mehr existieren,
     das JobOffer löschen (`DELETE /joboffers/{id}`).
   - **Vollständige Stellenausschreibung erfassen (Pflicht):** Beim `WebFetch` der
     Einzelanzeige den **kompletten Ausschreibungstext** übernehmen — nicht nur eine
     Kurzzusammenfassung. Dazu gehören: Einleitung/Unternehmensvorstellung, **Aufgaben/
     Tätigkeiten**, **Anforderungen/Profil**, **Wir bieten/Benefits**, Angaben zu
     Arbeitszeit/Vertragsart/Standort, Gehalt (falls genannt), Bewerbungsweg/Kontakt
     und Referenz-/Kennziffer. Text weitgehend **wortgetreu und vollständig** sichern
     (nur Navigations-/Cookie-/Footer-Boilerplate der Seite weglassen), inkl. der
     Gliederung/Überschriften. Dieser Volltext wandert in `beschreibung` (Schritt 6).
     Ist die Seite lang/abgeschnitten, `WebFetch` gezielt erneut aufrufen, um alle
     Abschnitte zu bekommen.
   - **`quelle_url` verifizieren:** Muss auf die **konkrete, noch aktive
     Einzelanzeige** zeigen (nicht Trefferliste/Suchseite). Deeplink defekt/Liste →
     per Suche den echten Einzel-Link finden (bevorzugt Firmenwebsite/Karriereseite),
     sonst verwerfen.
   - **Vermittler/Zeitarbeit aussortieren (Pflicht):** Zeigt der Treffer auf eine
     Personalberatung/Headhunter/Zeitarbeit statt den echten Arbeitgeber, **verwerfen**
     (nicht listen, nicht importieren). Bei Unsicherheit die inserierende Firma per
     `WebFetch` (Impressum/„Über uns") prüfen — Recruiting-/Personaldienstleister raus.
     Existiert dieselbe Stelle direkt auf der Firmen-Karriereseite, diese
     Original-Anzeige verwenden statt des Vermittler-Treffers.
   - **Bewerber-Kontakt-E-Mail recherchieren:** Die E-Mail-Adresse ermitteln, an die
     sich Bewerber wenden. Reihenfolge: (a) direkt in der Stellenanzeige genannte
     Bewerbungs-/Kontaktadresse; (b) Karriere-/Kontaktseite der Firma
     (`WebSearch` „<Firma> Karriere Kontakt Bewerbung E-Mail“, `WebFetch` der Seite);
     (c) allgemeine Bewerbungsadresse (`bewerbung@`/`jobs@`/`karriere@<domain>`) nur,
     wenn auf der Firmenseite belegt. **Nicht raten** — nur Adressen übernehmen, die
     belegt sind; sonst `kontakt_email` leer lassen und als „nicht gefunden“ markieren.
   - **Firmenadresse recherchieren (Pflicht):** Die **genaue Anschrift** des
     Arbeitgebers ermitteln (Straße, Hausnummer, PLZ, Ort) — und zwar die, die
     **exakt zu dieser Stelle passt**. Reihenfolge: (a) in der Stellenanzeige selbst
     genannter Einsatz-/Arbeitsort (oft unter „Standort"/„Einsatzort"/am Anzeigenende);
     (b) Impressum bzw. Kontakt-/Standortseite der Firma
     (`WebSearch` „<Firma> Impressum Adresse <Ort>“, `WebFetch` der Seite).
     ⚠️ **Adresse muss zur Stelle passen:** Hat die Firma **mehrere Standorte/
     Niederlassungen**, die Anschrift des **konkreten Arbeitsorts der Stelle** nehmen —
     **nicht** blind die Zentrale/Hauptsitz-Adresse, wenn die Stelle an einem anderen
     Standort ausgeschrieben ist. Nennt die Anzeige nur eine Stadt (`ort`), aber keine
     Straße, gezielt die zu **dieser Stadt** gehörende Niederlassungsadresse suchen und
     verifizieren. **Nicht raten** — nur eine belegte, zum Stellen-Ort passende Adresse
     übernehmen; sonst `adresse` leer lassen und als „nicht gefunden“ markieren.
     Passt die einzige auffindbare Firmenadresse **nicht** zum `ort` der Stelle
     (anderer Standort), lieber leer lassen als eine falsche Zentrale eintragen.

5. **Ergebnis präsentieren** als Tabelle: Firma · Stelle · Ort · **Adresse** ·
   Quelle (Board) · **verifizierter Link** · **Kontakt-E-Mail** · kurze
   Passt-Begründung. Sortierung: neue, klar passende Treffer **nach Nähe zu Gladbeck**
   (Gladbeck zuerst, dann Bottrop/Gelsenkirchen, dann Essen/Oberhausen, dann Dorsten/Marl).
   Fehlt Link, E-Mail oder Adresse, kennzeichnen.

6. **Importieren** — im **interaktiven** Modus nur nach Rückfrage/Bestätigung des
   Nutzers; im **autonomen Modus** (siehe unten) automatisch ohne Rückfrage. Jeden
   neuen Treffer als JobOffer einspielen (Upsert, idempotent) über den
   `bewerbungs-tracker`-Skill:
   ```bash
   ~/.claude/skills/bewerbungs-tracker/scripts/bt.sh POST /joboffers '{
     "external_id": "stellensuche-<slug(firma)>-<slug(stelle)>",
                                      // IMMER setzen und DETERMINISTISCH aus
                                      // firma+stelle bilden — NICHT aus der
                                      // Board-/Anzeigen-ID. Slug = normalisiert
                                      // wie der firma_slug (lowercase, ohne (m/w/d)
                                      // & Rechtsform, Interpunktion→"-"), z. B.
                                      // "stellensuche-musterfirma-it-systemadministrator".
                                      // So bekommt DIESELBE Stelle über jeden
                                      // Lauf UND jedes Board dasselbe external_id
                                      // → Server-Upsert greift zuverlässig statt
                                      // eine Dublette anzulegen. (Eine flüchtige
                                      // Board-ID würde je Quelle abweichen und so
                                      // Duplikate erzeugen — daher NICHT nutzen.)
     "quelle": "stellensuche",
     "firma": "…", "stelle": "…", "ort": "…",
     "adresse": "<genaue Anschrift des Arbeitsorts der Stelle: Straße Hausnr, PLZ Ort;
                 recherchiert & verifiziert, passend zum Stellen-Standort; sonst weglassen>",
     "gehalt": "…",
     "beschreibung": "<VOLLSTÄNDIGE Stellenausschreibung>",
                                      // Der komplette, in Schritt 4 per WebFetch
                                      // erfasste Anzeigentext: Aufgaben, Anforderungen/
                                      // Profil, Wir-bieten/Benefits, Arbeitszeit/
                                      // Vertragsart, Standort, Gehalt, Bewerbungsweg,
                                      // Referenz-/Kennziffer — wortgetreu und
                                      // vollständig, nicht kürzen/zusammenfassen.
                                      // Gliederung/Überschriften erhalten (Markdown
                                      // ok). Nur Seiten-Boilerplate weglassen.
     "quelle_url": "<verifizierter Einzel-Link, bevorzugt Firmen-Karriereseite>",
     "art": "Firmenwebsite",
     "anzeige_datum": "YYYY-MM-DD",
     "kontakt_email": "<recherchierte Bewerber-E-Mail, sonst weglassen>",
     "labels": ["Regional"]  // IMMER setzen: dieser Skill sucht ortsgebunden in
                             // den sieben Städten → Arbeitsort-Label "Regional".
   }'
   ```
   `art`-Enum: `E-Mail`, `Online-Portal`, `Indeed`, `StepStone`, `Firmenwebsite`,
   `Post`, `Initiativbewerbung`, `Arbeitsagentur`, `Sonstiges`. **Standard ist
   `Firmenwebsite`** (Original-Anzeige des Arbeitgebers). `StepStone` nie verwenden
   (ausgeschlossene Quelle); `Arbeitsagentur`/`Indeed` nur, wenn der Link direkt zur
   Arbeitgeber-Anzeige führt.

   **`409`-Antwort beim Import:** Steht der Job (trotz Vorfilter) auf der Blacklist,
   antwortet `POST /joboffers` mit **409** (`BlacklistConflict`) und nimmt ihn
   **nicht** auf. Das ist **kein Fehler** — als „übersprungen (Blacklist)" zählen
   und mit dem nächsten Treffer weitermachen, **nicht** mit `force` erzwingen.

7. **Direkt blacklisten (nach jedem erfolgreichen Import).** Sobald ein JobOffer
   angelegt wurde (Antwort **201** / `action:created`; bei `updated` ist der Job
   bereits erfasst), die **Firma sofort ganz** blacklisten, damit dieser Arbeitgeber
   in künftigen Läufen **mit keinem Stellentitel** wieder auftaucht (Regel „eine Firma
   nur einmal"). Per `typ: firma` sperren — der Server matcht firmenweit über
   `firma_slug` und deckt so abweichende Schreibweisen/Rechtsformen mit ab:
   ```bash
   ~/.claude/skills/bewerbungs-tracker/scripts/bt.sh POST /joboffers/blacklist '{
     "typ": "firma",
     "firma": "<firma wie importiert>",
     "grund": "auto: stellensuche-import <YYYY-MM-DD>"
   }'
   ```
   Server-Antwort **201** = geblacklistet. Normalisierung (Groß/Klein, `(m/w/d)`,
   Rechtsform, Umlaute) übernimmt der Server. Nur nach **echtem** Neuimport
   blacklisten — nicht bei einem 409-Skip (steht ja schon drauf) und nicht bei
   bloßem `updated`.

## Autonomer Modus (headless / geplant)

Wird der Skill **nicht-interaktiv** ausgeführt — d. h. ohne Nutzer, der bestätigen
kann (z. B. `claude -p "…" --dangerously-skip-permissions`, Cron/geplanter Lauf,
`ollama launch claude … -p …`) — im **autonomen Modus** arbeiten:

- **Ohne Rückfrage importieren:** Neue, geprüfte Treffer direkt als JobOffer
  einspielen (Schritt 6) **und anschließend blacklisten** (Schritt 7). Es gibt
  niemanden zum Bestätigen — nicht auf Eingabe warten.
- **Alle Prüfregeln gelten unverändert und strikt:** Existenz-Prüfung (Schritt 4),
  korrekter verifizierter Einzel-Link, Kontakt-E-Mail nur wenn belegt, **Firmenadresse
  nur wenn belegt und zum Stellen-Ort passend** (Schritt 4), die
  persistente Dedup **und der Blacklist-Filter** (Schritt 1/3) — importiere **nur**
  echte, live verifizierte, noch nicht erfasste und **nicht geblacklistete** Stellen.
  Im Zweifel **nicht** importieren (lieber auslassen).
- **Keine Bewerbungen anlegen/versenden**, keine Löschungen bestehender Bewerbungen,
  keine Generierung anstoßen — nur neue Jobangebote (`POST /joboffers`) einpflegen
  und den jeweils importierten Job blacklisten (`POST /joboffers/blacklist`).
- **Kurzbericht ausgeben** (für das Log): je Treffer `action`
  (created+blacklisted / updated / skip-dedup / skip-blacklist) mit Firma, Stelle,
  Ort, Link; am Ende Zähler „X neu importiert & geblacklistet, Y als Dublette/
  Blacklist übersprungen, Z verworfen (nicht verifizierbar)".

## Regeln

- **Nur sieben Städte.** Es werden **ausschließlich** Stellen mit Arbeitsort in
  Gladbeck, Essen, Gelsenkirchen, Oberhausen, Bottrop, Dorsten oder Marl gelistet/importiert.
  Alles außerhalb dieser sieben Städte (übriges Ruhrgebiet, reines Remote/Homeoffice ohne
  Sitz in einer der sieben Städte) wird **verworfen**. Priorität nach Nähe zu Gladbeck.
- **Label `Regional` setzen (Pflicht).** Jedes von diesem Skill importierte JobOffer
  bekommt `labels: ["Regional"]` (ortsgebundene Stelle in einer der sieben Städte).
  Kein Remote-/Homeoffice-Label — solche Stellen sind Sache des Skills
  `it-stellensuche-remote`.
- **Keine erfundenen Stellen.** Nur Jobs ausgeben, die per WebSearch/WebFetch real
  belegt sind. **`quelle_url` muss der korrekte, geprüfte Direktlink zur
  Einzelanzeige sein** (per `WebFetch` bestätigt) — keine Such-/Listenseiten, keine
  geratenen URLs. Kein verifizierbarer Einzel-Link → Treffer nicht listen/importieren.
- **Nur Original-Anzeigen echter Arbeitgeber.** Headhunter/Personalvermittler,
  Zeitarbeit/Arbeitnehmerüberlassung und **Stepstone** sind ausgeschlossen — weder
  listen noch importieren (siehe „Quellen-Politik"). Bevorzugt der Firmen-Direktlink;
  im Zweifel (Vermittler? Zeitarbeit?) die inserierende Firma prüfen und lieber
  verwerfen.
- **`beschreibung` = vollständige Ausschreibung.** Immer den kompletten, per WebFetch
  erfassten Anzeigentext (Aufgaben, Anforderungen, Benefits, Konditionen, Bewerbungsweg,
  Kennziffer) übernehmen — nicht kürzen oder zusammenfassen. Inhalt aus der realen
  Anzeige, nicht frei ergänzen.
- **Kontakt-E-Mail nicht erfinden.** `kontakt_email` nur setzen, wenn die Adresse in
  der Anzeige oder auf der Firmen-Karriereseite belegt ist; sonst weglassen.
- **Firmenadresse recherchieren, nicht erfinden — und passend zur Stelle.** `adresse`
  (Straße, Hausnummer, PLZ, Ort) im Web ermitteln und nur eine **belegte** Anschrift
  eintragen, die **genau zum Arbeitsort der Stelle** gehört. Bei mehreren Standorten
  die Niederlassung der ausgeschriebenen Stelle nehmen, **nicht** pauschal den
  Hauptsitz. Passt keine verifizierte Adresse zum Stellen-Ort, `adresse` leer lassen
  statt eine falsche Zentrale einzutragen.
- **Keine Doppelfunde — eine Firma nur EINMAL, auch über Läufe hinweg.** Vor dem
  Listen/Importieren immer `applied-set.sh` **und** `blacklist-set.sh` laden und
  jeden Kandidaten per `quelle_url`, `external_id` **und `firma_slug` (firmenweit)**
  sowie gegen die Blacklist abgleichen. **Steht die Firma schon im Applied-Set oder
  auf der Blacklist — egal unter welchem Stellentitel und egal in welcher
  Schreibweise/Rechtsform (`firma_slug` gleich ODER Präfix-Match, mind. 2 Tokens) —
  wird kein weiterer Treffer dieses Arbeitgebers ausgegeben oder importiert.** Auch
  **innerhalb eines Laufs** jede Firma nur **einmal** präsentieren (bei mehreren
  Stellen derselben Firma die am besten passende wählen). Beim Import die
  `external_id` **deterministisch aus `firma+stelle`** bilden, **nicht** aus einer
  Board-/Anzeigen-ID — so ergibt dieselbe Stelle über jeden Lauf/jedes Board dasselbe
  `external_id` (Server-Upsert statt Dublette). Der Server dedupliziert
  `POST /joboffers` über `external_id` (Upsert) und die Blacklist (409, firmenweit
  über `firma_slug`).
- **Blacklisten nach jedem Import (Pflicht, firmenweit).** Jeder frisch angelegte Job
  (`action:created`) wird direkt anschließend per `POST /joboffers/blacklist`
  (**`typ:firma`** — die ganze Firma) gesperrt (Schritt 7), damit dieser Arbeitgeber
  in Folgeläufen mit keinem Titel wieder auftaucht. Nicht blacklisten bei `updated`
  oder bei einem 409-Skip. Ein 409 beim `POST /joboffers` bedeutet „steht schon auf
  der Blacklist" → überspringen, nie mit `force` erzwingen.
- **Interaktiv: nicht ungefragt importieren** — erst zeigen, dann auf Bestätigung
  importieren. **Autonom/headless: automatisch importieren** (siehe „Autonomer
  Modus"). In **keinem** Modus Bewerbungen anlegen/versenden.
- Board-Aggregatoren-Duplikate (dieselbe Stelle auf mehreren Portalen) zu einem
  Eintrag zusammenfassen, bevorzugt mit Direkt-/Firmenwebsite-Link.
- Ist die Bewerbungs-Tracker-API nicht erreichbar (`GET /health`), Dedup nicht
  möglich → Nutzer warnen und Treffer ohne Dedup mit Hinweis liefern.

## Abhängigkeiten

- Tools: `WebSearch`, `WebFetch`.
- Skill `bewerbungs-tracker` (für Dedup-Daten, JobOffer-Import und Blacklist:
  `GET/POST /joboffers/blacklist`).
- Scripts: `scripts/arbeitsagentur.sh` (strukturierte Jobsuche-API der Bundesagentur
  für Arbeit — primäre Quelle, `search`/`detail`), `scripts/applied-set.sh` (erfasste
  Firmen), `scripts/blacklist-set.sh` (gesperrte Muster). `applied-set`/`blacklist-set`
  nutzen den `bt.sh`-Helfer des `bewerbungs-tracker`-Skills; `arbeitsagentur.sh` nutzt
  nur `curl` + `python3` (öffentliche API, kein Key nötig).
