inbox-sync

Der Bruecken-Skill zwischen “Handy-Notiz per Siri” und “Datei im Repo”. Zieht Emails die Marvin an sich selbst geschickt hat und legt sie als Rohmaterial in inbox/ ab. Einsortieren in Wiki / Tasks / Ideen macht wiki-maintenance in einem separaten Schritt — dieser Skill transportiert nur.

Trigger-Prinzip. Marvin schreibt sich normalerweise keine Emails selber. Jede Email von Marvin an Marvin ist also bewusst eine Inbox-Notiz. Kein Subject-Marker noetig, kein zusaetzliches Ritual. Das macht Siri-Diktat einfach: “Hey Siri, neue Mail an mich, Text: …“.

Was zaehlt als “Marvin”? Beide Konten: hello@marvinkuehlmann.com (business) und marvinkuehlmann@gmail.com (privat). Jede Kombination gilt:

FromToInbox-Mail?
hello@hello@ja
hello@marvinkuehlmann@ja
marvinkuehlmann@marvinkuehlmann@ja
marvinkuehlmann@hello@ja
Externeregalnein

1. Gmail durchsuchen (beide Accounts parallel)

Query pro Account: from:(hello@marvinkuehlmann.com OR marvinkuehlmann@gmail.com) to:(hello@marvinkuehlmann.com OR marvinkuehlmann@gmail.com) in:anywhere

  • in:anywhere damit Emails auch gefunden werden wenn Gmail sie in SPAM geschoben hat (passiert bei from=hello@ to=privat — Spoofing-Verdacht).
  • Accounts beide abfragen, identische Email kann in beiden Mailboxen landen (delivered_to unterscheidet sich). Dedupe laeuft ueber message_id (siehe naechster Schritt).

Dedupe: schon verarbeitete Emails ueberspringen

Vor dem Zeigen der Treffer alle .md-Files in inbox/ lesen und gmail_id-Werte aus dem Frontmatter sammeln. Jede Email deren id bereits in dieser Menge ist — skippen. Das File-System ist die Dedupe-Quelle, nicht ein Gmail-Label.

Warum File-basiert: Das MCP-Toolset hat kein create_label. Ein agent-inbox-processed-Label anzulegen ist nicht moeglich ohne zusaetzliches Tooling. File-Dedupe ist direkter und braucht keinen Gmail-State.

Wenn 0 neue Treffer (nach Dedupe) in beiden Accounts: Ausgabe "Keine neuen Inbox-Emails." und STOP. Keine leere Ordner-Aktion, keine falsche Betriebsamkeit.

Edge Case: echte Self-Emails ausschliessen

Seltene Faelle wo Marvin doch MAL eine Mail an sich selbst schreibt, die kein Inbox-Material ist:

  • Drafts die er sich zum spaeter-schicken ablegt
  • Google-Docs/Drive-Benachrichtigungen die technisch “von mir” aussehen (Sender kann vom Service manipuliert sein)

Darum gibt es Schritt 2 (Preview) — Marvin kann dort einzelne Mails ausschliessen. Nie stillschweigend importieren.

2. Pro Email Preview zeigen

Bevor du schreibst, zeig eine Kurz-Uebersicht:

📥 {n} neue Inbox-Emails gefunden:

  1. [privat→privat]   2026-04-17 18:42 — "Becker Stahl Mittwoch"
                       → "Alex hat angerufen, Mittwoch 14 Uhr..."
  2. [hello→privat]    2026-04-17 19:15 — "Idee Podcast Skill"
                       → "Ich hatte eben die Idee, dass wir..."
  ...

Alle in `inbox/` ablegen und Emails aufraeumen? [j/n/auswaehlen]

Warum Preview: Marvin soll eine versehentlich self-adressed Email (Draft, Google-Benachrichtigung) noch abfangen koennen. Nach dem OK laeuft der Skill durch.

Auswahl-Modus: Wenn Marvin einzelne Emails skippen will (nur 1 und 3), die restlichen bleiben unberuehrt (kein File, keine Gmail-Aktion).

3. Pro Email ein File schreiben

Zielpfad: inbox/YYYY-MM-DD-<slug>.md

  • YYYY-MM-DD = Email-Empfangs-Datum (nicht heute — konsistent mit dem Moment wo der Gedanke kam)
  • <slug> = aus dem Betreff, ohne [inbox]-Marker, kebab-case, max 60 Zeichen, Umlaute aufgeloest (ae/oe/ue/ss — siehe conventions.md §1)
  • Konflikt-Strategie: Wenn File schon existiert (gleicher Tag, gleicher Slug) → suffix -2, -3

File-Inhalt:

---
description: "Roh-Inbox-Eintrag via Siri/Email. Noch nicht einsortiert."
last_reviewed: {Datum-heute}
source: email
source_account: {delivered_to-Adresse}
source_message_id: {Email-Message-ID}
gmail_id: {Gmail-message-id, fuer Dedupe}
received_at: {ISO-Timestamp aus date-Header}
---
 
# {Betreff}
 
{Email-Body als Plain-Text — HTML strippen, signatur-ueblich bereinigen (Gmail-typische `--`-Trenner, `"Von meinem iPhone gesendet"`, Attachments-Footer etc. raus)}

Keine Interpretation, keine Zusammenfassung. Nur transportieren. wiki-maintenance ist fuer’s Einsortieren zustaendig, dieser Skill ist reiner Kurier.

Betreff-Slug-Sonderfall: Wenn der Betreff leer oder generisch ist (z.B. nur “Inbox”, “Notiz”, “(kein Betreff)”): slug aus den ersten ~5-8 Woertern des Body bauen. Der H1-Titel kann trotzdem der Original-Betreff bleiben.

HTML-Bereinigung: Wenn die Mail nur HTML ist (kein Plain-Text-Teil), den HTML-Body in Plain-Text konvertieren. Keine Links/Formatting erhalten — falls Marvin Formatting braucht, schreibt er es ordentlich beim Einsortieren.

Siri-Typos tolerieren: Spracherkennung macht Fehler (“Das eine Test-E-Mail ist” statt “Dies eine Test-E-Mail ist”). Body nicht korrigieren — Marvin weiss was er gemeint hat, Korrektur wuerde Zusatz-Risiko fuer Inhalts-Aenderung einfuehren.

4. Email aufraeumen

Fuer jede erfolgreich geschriebene Email:

  1. SPAM-Label entfernen (falls gesetzt) — die Mail soll nicht im Spam-Ordner verschwinden, wir wollen sie in “Alle Nachrichten” auffindbar halten.
  2. UNREAD-Label entfernen — gelesen-Markierung, sie ist ja verarbeitet.
  3. INBOX-Label entfernen (falls gesetzt) — archivieren. Die Mail ist in “Alle Nachrichten” noch da.

Nicht loeschen. Die Email bleibt in “Alle Nachrichten” erhalten, falls spaeter noch was nachgeschaut werden muss. Audit-Spur via Gmail-Search: from:me to:me zeigt alles was jemals als Inbox-Notiz gesendet wurde.

Dedupe ist File-basiert, kein Label noetig. Der Skill liest gmail_id aus allen inbox/*.md Files im naechsten Lauf. Die Mail wird nicht erneut gezogen. Siehe Schritt 1.

Fehler-Handling: Wenn das Schreiben des Files fehlschlaegt, nicht die Email verändern — sonst geht der Kontext verloren. Schreib den Fehler in die Zusammenfassung und verarbeite den Rest weiter.

5. Zusammenfassung zeigen

Format:

✅ {n} Inbox-Emails verarbeitet:
  1. inbox/2026-04-17-becker-stahl-mittwoch.md (privat)
  2. inbox/2026-04-17-idee-podcast-skill.md (business)
  ...

{optional, bei Fehlern:}
⚠️ {n} Fehler:
  - "Idee XYZ" (business): {Fehler-Text}

Naechster Schritt: `wiki-maintenance` laufen lassen um die Inbox einzusortieren.

Die letzte Zeile ist wichtig — macht den Chain zu wiki-maintenance sichtbar ohne ihn automatisch auszufuehren (Marvin entscheidet).

6. Edge Cases

  • Anhaenge in der Email: Noch nicht unterstuetzt. Wenn eine Email Anhaenge hat, das File trotzdem schreiben (Text-Body), am Ende eine Zeile **Anhang in Email — nicht importiert:** {Dateiname(n)} anhaengen. Marvin entscheidet was damit passiert. Phase-2-Verbesserung: Anhaenge nach inbox/attachments/ extrahieren.
  • Sehr kurze Email (z.B. “test”): trotzdem schreiben. Wiki-maintenance wird das wahrscheinlich loeschen.
  • Threads (Replies auf frueheren Inbox-Email): Jede Message als eigenes File, Slug mit -reply Suffix.
  • Externer Absender an mich: Kein Inbox-Material. Die Query filtert das schon raus — Sicherheitshalber vor dem Schreiben nochmal from pruefen.
  • Draft/Self-Email die KEIN Inbox-Material ist: Marvin skippt per Preview (Schritt 2). Skill macht dann nichts — File nicht schreiben, Email nicht anfassen.

7. Side-Effects-Uebersicht

AktionWannReversibel?
File in inbox/ schreibenpro Email, nach OKJa (manuell loeschen)
SPAM-Label entfernennach File-WriteJa (in Gmail wieder setzen)
UNREAD-Label entfernennach File-WriteJa (in Gmail wieder setzen)
INBOX-Label entfernen (archivieren)nach File-WriteJa (Email wieder in Inbox ziehen)

Keine Email wird geloescht. Keine externe Kommunikation.

  • _context — Inbox-Zweck und Befuell-Wege
  • SKILL — sortiert die Inbox ein
  • config-planning — Email-Account-Strategie (welcher Account ist welcher)
  • conventions §1 — Naming (kebab-case, Umlaut-Aufloesung)
  • CLAUDE — Routing-Tabelle (Mobile-Notiz → inbox-sync)
  • gsuite — Gmail-MCP (beide Accounts)