Files
jobbi-bewerbung/agent/skills/it-stellensuche/SKILL.md
T
thomasandClaude ce844412e5 Jobsuche: Agent pro Benutzer in isoliertem Docker-Container
Jeder Suchlauf läuft nun in einem frischen Container pro Benutzer, dessen
pro-Benutzer-Home als ~/.claude gemountet ist — Memories und Session-Contexte
liegen damit strikt getrennt pro Benutzer. Die Such-Skills sind Shared-Code
aus dem Image und werden im Container nur nach ~/.claude/skills verlinkt.

Der Host-Runner startet pro Lauf `docker run --rm` und führt bis zu
JOBSUCHE_MAX_PARALLEL (Default 4) Läufe parallel über verschiedene Benutzer
aus (jeder hat eigenen Ollama-Key = getrennte Rate-Limits). Der alte gemeinsame
~/.claude-Pfad wird vom Runner nicht mehr beschrieben.

- source/agent/: neues Agent-Image (Dockerfile + entrypoint + drei Skills)
- scripts/jobsuche-runner.js: agentStarten als docker run, ensureAgentDir, runPool
- scripts/jobsuche-runner.sh + bin/-Kopie: Image-Guard
- package.json: docker:build-agent (lokal, ohne Registry-Push)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-14 15:41:22 +02:00

38 KiB
Raw Blame History

name, description
name description
it-stellensuche 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-trackerGET /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:

    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:

    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 1520 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:

    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 einsetzenOR, 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 1015 verschiedene Queries ab statt 12.

    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 (37). Der Firmen-Direktlink ist hier ohnehin schon die bevorzugte quelle_url.
  1. 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).
      • firmadieselbe 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.
  2. 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 „ 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 „ Impressum Adresse “, 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.
  3. 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.

  4. 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:

    ~/.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.

  5. 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:

    ~/.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).