Drei Skills + Importer + Migration der 5 existierenden Venues.
Skills (alle repo-lokal in .claude/skills/):
- seepuls-curate-venue: 5-Stufen-Pipeline (Plan → Recherche → Design
→ Validate → Publish), Reviewer-Stops Pflicht, Nominatim-Geocoding
mit Politeness, YAML als Output. Bulk-Mode für >10 Venues.
- seepuls-validate-venue: read-only, 8 Checks (slug-unique,
country-enum, region-enum, coords-plausibel, description-länge,
robots-allow, source-coverage, enum-fit).
- seepuls-curate-events: zwei Modi (Crawl via admin-API mit
Service-Key, oder Manual aus User-Input). DB-as-SOT (nicht YAML),
weil Events kurzlebig sind.
Importer:
- apps/api/src/jobs/import-venues.ts: liest curated/venues/*.yml,
upsert in seepuls.venues, idempotent (zweiter Run = 0 inserted,
N updated). Zod-Validation der YAML-Form.
- pnpm db:import-venues script.
- Pattern an zitare-Importer orientiert.
SOT-Migration der 5 bestehenden Venues:
- apps/api/src/data/curated/venues/{museum-rosenegg,
seemuseum-kreuzlingen, bodensee-planetarium-kreuzlingen,
rosgartenmuseum, archaeologisches-landesmuseum-konstanz}.yml
- README.md mit Format-Doku.
Doku:
- seepuls/docs/CURATOR.md: Workflow-Übersicht, verweist auf
mana/docs/CONTENT_PIPELINES.md als Cross-Repo-Pattern.
Lokal validiert (gegen Postgres :5441):
- 1. Lauf: 5 inserted ✓
- 2. Lauf: 0 inserted, 5 updated ✓ (idempotent)
- type-check + 43/43 Tests grün.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
10 KiB
| name | description | argument-hint | allowed-tools | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| seepuls-curate-venue | Legt eine Venue im Seepuls-Korpus an oder reichert sie an — Recherche → strukturierte Felder → Geocoding → Validate → YAML in apps/api/src/data/curated/venues/<slug>.yml → Import. Mit Reviewer-Stops, Quellen-Permalinks, Compliance-Veto. | <venue-name-oder-url> [--slug <existing-slug>] [--country DE|CH|AT|LI] [--region <slug>] |
|
/seepuls-curate-venue — Curator-Workflow für eine Venue
Du legst eine Venue (Veranstaltungsort) im Seepuls-Korpus an oder
reicherst sie an. YAML in apps/api/src/data/curated/venues/<slug>.yml
ist die SOT — DB-Eintrag entsteht durch pnpm db:import-venues.
Schwester-Skill von /seepuls-validate-venue
und /seepuls-curate-events. Cross-Repo-
Best-Practices: ../mana/docs/CONTENT_PIPELINES.md.
Wann benutzen
- User will eine neue Venue anlegen (Museum, Club, Kulturhaus, Bar, Verein, Festival-Spielstätte) für die Bodensee-Region (DE+CH+AT+LI).
- User will eine bestehende Venue korrigieren (Adresse, Beschreibung, Logo, Social).
- User hat eine konkrete URL und will daraus einen Eintrag.
Für die automatische Crawl-Pipeline (mana-research → mana-llm →
Reviewer-Stop) ist POST /api/v1/admin/venues/from-url der Pfad — er
schreibt direkt in DB mit crawl_status='pending-review'. Dieser Skill
hier ist der manuelle Pfad mit YAML-as-SOT, idempotent re-importierbar.
Pflicht-Lektüre vor erstem Run
seepuls/STATUS.md— Phasenstand der App.seepuls/apps/api/src/data/curated/venues/README.md— YAML-Format.seepuls/docs/CURATOR.md— Workflow-Übersicht.mana/docs/AGGREGATOR_POLICY.md— Hard-Rules (robots.txt, Attribution, ≤ 200 Zeichen Description).mana/docs/CONTENT_PIPELINES.md— generelles Pipeline-Pattern.
Inputs
- Venue-Name oder Website-URL (Pflicht) — z.B.
"Museum Rosenegg Kreuzlingen"oder"https://museumrosenegg.ch". --slug <existing>(optional) — bestehenden Eintrag anreichern.--country DE|CH|AT|LI(optional) — wenn aus dem Namen nicht eindeutig. AskUserQuestion bei mehrdeutigen Treffern (z.B. „Stadthaus" — welches?).--region <slug>(optional, defaultbodensee) — eine der curated Regions (bodensee/hegau/thurgau-west/oberschwaben).--no-import(optional) — Stage-5 überspringen, nur YAML schreiben (für dry-run / Review).
Workspace
~/Documents/seepuls-drafts/<slug>/
├─ plan.md Stufe-1-Output: Name, Country/Region, Source-Kandidaten
├─ research/
│ ├─ sources.md Quellen mit Permalinks + Zugriffsdatum
│ └─ notes.md Roh-Notizen aus WebFetch
├─ design/
│ └─ venue.yml Stufe-3-Vorschlag (gleiche Form wie curated/venues/*.yml)
├─ validate/
│ └─ report.md Output von /seepuls-validate-venue
└─ publish/
└─ import.log Output von `pnpm db:import-venues`
<slug> = kebab-case aus Name. Drafts bleiben liegen als Audit-Trail.
Pipeline (5 Stufen)
Stufe 1 — Plan
- Workspace anlegen:
mkdir -p ~/Documents/seepuls-drafts/<slug>/{research,design,validate,publish}. - Slug bestimmen: kebab-case aus Name, ohne Stop-Wörter
(„Museum X" →
museum-x). Bei Konflikt mit existing:<slug>-2oder ortsspezifischer (museum-x-konstanz). - Existenz-Check:
Wenn YAML existiert: User fragen ob ergänzen oder neuer Slug.ls seepuls/apps/api/src/data/curated/venues/<slug>.yml 2>/dev/null docker exec seepuls-postgres psql -U seepuls -d seepuls -tAc \ "SELECT slug FROM seepuls.venues WHERE slug='<slug>'" plan.mdmit:- Venue-Name (1 Zeile)
- Country + Region (Begründung warum diese Region)
- Source-URL-Kandidaten (offizielle Website, ggf. Wikipedia)
- Streitfälle (z.B. „mehrere gleichnamige Orte" — welcher?)
- Reviewer-Stop: User sieht Plan, sagt go oder korrigiert Slug/Region.
Stufe 2 — Recherche
- WebFetch der offiziellen Website — Name, Adresse, Beschreibung, Logo-URL, Social-URLs, Öffnungszeiten-Hinweis.
- Wikipedia-Cross-Check (optional) — bei historischen oder
prominenten Orten. Permalink mit
oldid. - Adresse präzise erfassen — Straße + Hausnummer + PLZ + Ort.
research/sources.md: nummerierte Quelle, jede mit:- Titel + URL
- Zugriffsdatum (ISO
YYYY-MM-DD) - Permalink wenn möglich (Wikipedia
oldid)
research/notes.md: Roh-Texte, Adress-Varianten, evtl. abweichende Schreibweisen. Streitfälle (z.B. „Website sagt Strasse, Wikipedia sagt Straße") markieren.
Stufe 3 — Design + Geocoding
- Nominatim Forward-Geocode für die Adresse:
Politeness Pflicht: User-Agent mit Kontakt-Mail, ≥ 1.1 s zwischen Requests. Bei mehreren Treffern: AskUserQuestion mit beiden Optionen.UA='seepuls/0.0.1 (+https://seepuls.mana.how; kontakt@mana.how)' curl -sf -H "User-Agent: $UA" --max-time 10 \ --data-urlencode 'q=Straße Nr, PLZ Ort' \ --data 'format=json&limit=2&countrycodes=de,ch,at,li' \ -G 'https://nominatim.openstreetmap.org/search' \ | jq -r '.[] | "\(.lat),\(.lon) \(.display_name)"' - Plausibilität prüfen: lat ∈ [47.4, 47.9], lng ∈ [8.5, 9.7] (Bodensee-Bounding-Box). Außerhalb → Plan-Stop, möglich falsche Region.
design/venue.ymlschreiben in der Form auscurated/venues/README.md. Felder:slug(aus Plan)name(offizielle Schreibweise)countryCode(ISO DE/CH/AT/LI)regionSlug(curated; defaultbodensee)city,addresscoordinates: {lat, lng}aus Nominatimdescription(≤ 200 Zeichen, in Originalsprache, kein LLM-Re-Phrasing — direkte Übernahme oder leichte Kürzung)websiteUrl,logoUrl(oder null),socialUrls(Map)source: url + domain + accessedOn + refscrawlStatus: manual-entryattributionRequired: true
- Reviewer-Stop: User sieht die YAML, sagt go oder korrigiert.
Stufe 4 — Validate
Skill /seepuls-validate-venue <slug> aufrufen. Read-only, schreibt
validate/report.md mit 7 Checks (siehe Schwester-Skill).
Bei roten Items: nicht eigenmächtig fixen — User entscheidet welche Stufe nochmal durch.
Stufe 5 — Publish (YAML in SOT + Import)
- YAML kopieren nach
seepuls/apps/api/src/data/curated/venues/<slug>.yml. - Compliance-Veto via Sub-Agent:
Agent(subagent_type="mana-compliance", prompt="<diff der venue.yml>")- ✅ → weiter.
- ⚠️ → User informieren.
- 🛑 → abbrechen. YAML aus curated/ entfernen.
- Import:
Output incd seepuls && pnpm --filter ./apps/api db:import-venuespublish/import.log. Idempotent (zweiter Run = 0 inserted, 1 updated). - Cloudflare-Tunnel-Pause unnötig — die public Read-API zeigt die Venue sofort (keine Build-Cache-Invalidation nötig, Astro-Web ist SSR).
- Smoke:
curl --resolve seepuls-api.mana.how:443:188.114.96.12 -s \ 'https://seepuls-api.mana.how/api/v1/venues/<slug>' | jq
Anti-Halluzinations-Regeln
- Niemals Adresse oder Koordinaten raten. Wenn Nominatim nichts findet: stoppen, User fragen, Adresse manuell verifizieren.
- Niemals Description erfinden oder LLM-paraphrasieren. Direktes Zitat aus offizieller Quelle, ≤ 200 Zeichen. Wenn länger: kürzen am Satz-Ende, nicht umformulieren.
- Niemals geratene Social-URLs. Wenn die Website keinen Insta-Link
hat:
socialUrls: {}, nicht raten. - Niemals
logoUrlmit Wikipedia-Logo befüllen — nur das offizielle Logo von der Venue-Website (Hot-Link gemäß AGGREGATOR_POLICY §3), odernull.
Bulk-Mode (>10 Venues auf einmal)
Eine Curated-Liste (z.B. „alle Konstanzer Museen", „alle Konzert-Lokale Kreuzlingen") als Master-Quelle. Dann:
- Curated-Listings-Site als Quelle (z.B. konstanz.de/tourismus/museen, thurgau-bodensee.ch/freizeit/museen).
- Sampling-Reviewer-Stop: 5 zufällige Venues + Streitfall-Liste.
- Skript-getrieben: Python-Heredoc liest CSV (slug, name, address, website) und produziert N YAMLs. Geocoding-Loop mit Politeness-Delay.
- Atomic-Import:
pnpm db:import-venuesmacht alle in einer Transaction.
Reviewer-Stops sind Pflicht
Nach Stufe 1 (Plan) und Stufe 3 (Design + Geocoding), vor Stufe 5 (Publish). Auch wenn der User „mach einfach" gesagt hat. Stops sind kurz (Markdown-Preview + ja/nein), retten den Korpus vor falschen Adressen.
Was dieser Skill NICHT macht
- Events anlegen —
/seepuls-curate-eventsist Schwester-Skill. - Crawl-Pipeline triggern — der admin-Endpoint
/api/v1/admin/venues/from-urlist der automatische Pfad (Service-Key Pflicht). - Live-DB direkt schreiben — YAML ist SOT, Import macht den Rest.
- DSGVO-Sicht — Venue-Daten sind public-aggregierte Infos, keine PII. Personen-Daten (Veranstalter:innen-Mails etc.) gehören nicht ins YAML.
Dependencies
pnpm db:import-venues—apps/api/src/jobs/import-venues.tsdocker exec seepuls-postgres psql— Slug-Existenz-Checks- Nominatim-API (OSM, gratis, ≥ 1 req/s Politeness)
- Sub-Agent
mana-compliancefür Veto
Offene Punkte
- Logo-Hot-Link-Verifikation. Manche Websites haben
Hot-Link-Schutz; Logo lädt im Browser, aber nicht im img-Tag eines
anderen Hosts. Beim Smoke-Check (Stufe 5d) im Browser prüfen oder
fallback
logoUrl: null. - Slug-Konsistenz mit ECOSYSTEM-City-Tags. Wenn eine Stadt mehrere
Venues hat (Konstanz: Rosgarten + ALM): keine Konvention für
<venue>-<stadt>vs nur<venue>. Aktuell: Eindeutigkeit reicht. - Wikidata-Anbindung. Zitare nutzt Wikidata für Author-Enrich; bei Venues gibt es Wikidata-Properties für viele Museen. Optional zur V2 dazu.
Referenzen
- Format:
apps/api/src/data/curated/venues/README.md - Workflow-Übersicht:
seepuls/docs/CURATOR.md - Schwester-Skill:
/seepuls-validate-venue,/seepuls-curate-events - Cross-Repo-Best-Practices:
../mana/docs/CONTENT_PIPELINES.md - Aggregator-Policy:
../mana/docs/AGGREGATOR_POLICY.md