2016judea/sms-native-product

Baue ein Produkt, dessen Schnittstelle Textnachrichten sind – „keine App, keine Webseite“, „sie schreiben einfach einer Nummer“, „Chatte mit unserem Agenten direkt via SMS“, „können wir das per Text machen?“, „ein SMS-Bot“, „ein Telegram-Bot“, „mach es zu einem Gruppenchat“, „minimale Reibung“. Funktioniert auch, wenn es bereits schiefgelaufen ist – „meine Kampagne wurde abgelehnt“, „unsere Nummer ist blockiert“, „die Texte kommen nicht an“, „warum muss ich mich registrieren“. Deckt die Hürde ab, die entscheidet, ob ein solches Produkt überhaupt senden kann (US-A2P-10DLC-Registrierung, SHAFT-Inhaltsregeln, permanente Ablehnungscodes), Group-MMS aus Code, was jeder Kanal nicht kann, eine Architektur, die den Verlust des Kanals überlebt, und die Absicherung modell-umgeschriebener Benutzerinhalte.

Was ist sms-native-product?

Dieses Skill beschreibt, wie man ein Produkt entwickelt, dessen Benutzerschnittstelle ausschließlich aus Textnachrichten (SMS, Telegram, WhatsApp) besteht – ohne App oder Website. Der Fokus liegt darauf, die regulatorischen und technischen Hürden der US-amerikanischen A2P-10DLC-Registrierung (z. B. SHAFT-Inhaltsregeln und permanente Ablehnungscodes wie 30953 oder 30885) zu verstehen und zu umgehen, bevor mit dem Design begonnen wird. Es behandelt die Einschränkungen verschiedener Kanäle (z. B. keine Gruppen-MMS auf WhatsApp, keine Telefonbuch-API im Browser) und bietet eine bewährte Architektur, die den Verlust eines Kanals überlebt, indem der Transport als austauschbare Datei implementiert wird. Das Skill betont die Bedeutung eines Simulators, der den Produktionspfad testet, sowie die korrekte Handhabung von Benutzereingaben (STOP/HELP vor allem anderen) und die Absicherung von KI-umgeschriebenen Inhalten.

Funktioniert mit✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/2016judea/brick-mortar-skills/tree/HEAD/skills/sms-native-product

Installed? Explore more Produktivität & Zusammenarbeit skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Produkte, deren Schnittstelle Textnachrichten sind

Der Reiz ist real: Leute mögen es nicht, Apps zu installieren oder Websites zu besuchen, aber jeder kann texten. Der Haken ist, dass Sie den Kanal nicht besitzen. Die US-Carrier tun das, und sie haben eine Inhaltsrichtlinie und einen Genehmigungsprozess, der Sie dauerhaft ablehnen kann. Diese Hürde entscheidet, was das Produkt sein darf, und kommt daher zuerst.


Schritt 0 – die Hürde. Mach das vor dem Design, nicht danach.

Seit Februar 2025 blockieren US-Carrier nicht registrierten A2P-Verkehr vollständig, daher müssen eine Marke und eine Kampagne genehmigt werden, bevor auch nur eine Nachricht gesendet wird. Lies die aktuellen Fehlerdokumentationen jedes Mal neu; die Carrier-Richtlinie ändert sich.

CodeAuslöserErneute Einreichung?
30953explizite/anzügliche Sprache, oder eine verlinkte Seite, die „pornografische, Escort-, Dating- oder Erwachsenenunterhaltungsinhalte“ hostetNein
30885„hohes Risiko“ – irreführendes Marketing oder eine Registrierung, die den Traffic falsch darstelltNein
30898zu viele Marken auf einer EIN oder eine Registrierung, die wie eine Dublette aussiehtJa, mit Begründung

Regel: Nenne die Inhaltskategorie des Produkts in der ersten Antwort laut und sag, ob sie auf dieser Liste steht. Wenn die Kategorie (z. B. Dating) buchstäblich ein Schlüsselwort in einer Ablehnungsregel ist, ändert das Finden in Minute fünf die Architektur, den Landing-Text und den Ausweichplan. SHAFT ist die Abkürzung: Sex, Hate, Alcohol, Firearms, Tobacco – plus Cannabis, und Dating reitet mit.

Regel: Registriere ein Nebenprojekt als Einzelunternehmermarke, nicht unter der EIN eines bestehenden Unternehmens. Risikomuster folgen der Steuer-ID (30898), daher darf eine Ablehnung eines Nebenprojekts nicht die Sendebereitschaft deines Hauptgeschäfts beeinträchtigen. Einzelunternehmer ist auf Einzelpersonen ohne Steuer-ID beschränkt; der Durchsatz ist niedrig, und niedrig ist für eine Beta völlig ausreichend.

Regel: Baue niemals eine Tarn-Landingpage, um eine Kampagne genehmigt zu bekommen. Eine Seite, die verbirgt, was der Traffic tatsächlich ist, ist das 30885-Muster und verwandelt ein Ein-Nummern-Risiko in ein Risiko für jede jemals registrierte Nummer. Lege die Chancen klar dar und lass den Eigentümer entscheiden.

Beschreibe den Dienst danach, was er mechanisch tut, und nur, wenn das wahr ist (z. B. Journaling und Verantwortlichkeit in kleinen Gruppen, wenn das ist, was die Nachrichten sind). Wenn keine wahre Beschreibung die Hürde passiert, ist die Antwort ein anderer Kanal, nicht ein besserer Euphemismus.

Die Prüfung belohnt Fakten, auf die man zeigen kann: Nur-Inbound-Opt-in, Gesprächsvolumen, keine Links in wiederkehrenden Nachrichten, STOP vor allem anderen behandelt, explizite Inhalte an der Tür abgewiesen.

Schritt 0.5 – lies das Briefing nach ZAHLEN und OBJEKTEN, nicht nach Absicht

Behalte das Briefing des Gründers wörtlich als README.md und sag in CLAUDE.md, dass es über jedem Engineering-Dokument steht.

Regel: Bevor du eine Zustandsmaschine schreibst, liste jede Dauer im Briefing und jedes Nomen, auf das sie wirkt. Wenn zwei Dauern existieren, sind sie zwei Features. Ein Briefing mit einer einwöchigen Verzögerung für Antworten von Freunden, die den Autor erreichen und einer zweiwöchigen Sperre für das eigene Update des Autors ist leicht zu einem einzigen siebentägigen Halt auf den Eintrag zusammenzufassen – das eine Objekt, um das es bei keiner der Verzögerungen ging – und jeder nachgelagerte Fehler folgt aus dieser Zusammenlegung.

Regel: Benenne das Objekt jeder Verzögerung – „gehalten VOR wem“. Vor Freunden gehalten und vor dem Autor gehalten sind gegensätzliche Produkte.

Regel: Wenn das wörtliche Design des Briefings auf dem Kanal nicht erzwungen werden kann, sag es und nenne die Alternativen – wähle nicht stillschweigend das Erzwingbare. (Der Ersteller eines Gruppenchats ist ein Mitglied davon, daher kann kein Code die Antworten der Gruppe von ihm zurückhalten.) Das ist eine Prämissenentscheidung, und Prämissenentscheidungen gehören dem Eigentümer.

Ein kohärentes Fehllesen fühlt sich nicht wie eines an. Behalte einen ersetzten Designabsatz durchgestrichen an Ort und Stelle, anstatt ihn zu löschen; es zeigt einer späteren Sitzung, wie das Briefing falsch gelesen wurde.

Schritt 1 – was der Kanal kann und was nicht

  • Gruppen-SMS aus Code funktioniert. Twilio Conversations macht Gruppen-MMS nur auf +1-Langcodes – nicht gebührenfrei, nicht auf Kurzcodes – begrenzt auf 10 Teilnehmer inklusive deiner eigenen Nummer. Behaupte nichts anderes aus dem Gedächtnis.
  • Gruppen-MMS-SMS-Teilnehmer haben eine Adresse und keine ProxyAddress, daher bedient eine Nummer jeden Raum – aber die Teilnehmer/Proxy-Eindeutigkeitsregel (50425) hat kein dokumentiertes Verhalten für teilnehmer ohne Proxy. Gestalte niemals viele gleichzeitige Räume, die sich eine Nummer und einen Teilnehmersatz teilen. Ein dauerhafter Raum pro Person hat einen stabilen Teilnehmersatz.
  • Eine Webseite kann kein iPhone-Adressbuch lesen. Die Contact-Picker-API ist nur Chrome-auf-Android. „Kontakte synchronisieren“ ist tot bei Ankunft; ersetze es durch eine Zeile, die der Benutzer weiterleitet – die eingehende SMS des Empfängers ist der Einwilligungsnachweis, den die Carrier ohnehin wollen.
  • Ein Telegram-Bot kann keine Gruppe erstellen oder jemanden zu einer hinzufügen, und mit aktiviertem Datenschutzmodus hört er nur auf Befehle, die an ihn adressiert sind. Beides hilft: Der Ersteller fügt den Bot zu dem Chat hinzu, den er bereits hat, und allgemeines Geplauder kann nicht mit Eingaben verwechselt werden. Das Erstellen eines Bots erfordert einen Menschen in @BotFather (keine API); frage nach dem Token.
  • WhatsApp Cloud API hat kein Gruppen-Messaging.
  • iMessage-APIs (Sendblue, LoopMessage) machen blaue Blasen und echte Gruppenchats, kosten aber etwa 100 $/Leitung/Monat zuzüglich Einrichtungsgebühren.

Schritt 2 – Architektur, die den Verlust des Kanals überlebt

Weil der Kanal abgelehnt werden kann, muss der Transport eine Datei sein:

machine.js   pure: (context, event) -> {replies, effects}    kein I/O, keine Uhr
engine.js    Kontextaufbau -> machine -> effects          der gesamte Pfad
effects.js   createEffects({db, channel})                    führt Entscheidungen aus
twilio.js  / telegram.js                                     austauschbar
api/*.js     dünne Shim-Dateien über engine.js               ~10 Zeilen jede
sim/         In-Memory-DB + Konsolenkanal
  • Der Entscheidungskern nimmt now als Argument und berührt kein Netzwerk. Jeder Fehler in dieser Produktklasse ist ein Sequenzierungsfehler (eine Erinnerung, die zweimal feuert, eine Nachricht an einen leeren Raum, ein gehaltener Gegenstand, der nie ankommt), und keiner ist gegen ein Live-Netzwerk und einen Sieben-Tage-Timer testbar.
  • Adapter sind Argumente, niemals Importe, in der Effektebene – derselbe Refaktor, den der Simulator und der Ausweichkanal benötigen.
  • Keine Logik innerhalb eines HTTP-Handlers. Kanalspezifisches Onboarding, das in api/telegram.js geschrieben ist, ist nicht testbar; extrahiere es.

Schritt 3 – treibe es an, test es nicht nur

node sim/drive.js          skriptbasiert: der gesamte Zyklus, eine Woche übersprungen, die Wächter
node sim/drive.js --repl   tippe als beliebige Zahl; /as <n>  /jump <Tage>  /state
  • Der Simulator muss den Produktionspfad ausführen, keine parallele Kopie.
  • Erwarte, dass eine erste Fahrt mehrere echte Fehler aufdeckt, die Unit-Tests nicht erreichen können: ein Raum, der sich selbst begrüßt, bevor jemand drin ist, ein nackter Wochentag für ein Datum eine Woche entfernt, eine Erinnerung, die nicht sagt, auf welches Element sie sich bezieht, ein Raum, dessen Mitglieder alle gegangen sind.
  • Wenn ein Test rot wird, überprüfe zuerst den Test (ein Datumsregex, der das Komma in „Sun, Aug 30“ nicht erlaubt; ein doesNotMatch, das auf eine andere, legitime Nachricht feuert).
  • Entscheide oder drucke niemals von einem Store-gestempelten Zeitstempel. Der Store schreibt created_at von der echten Uhr, nicht der injizierten now des Engines, also lügt er unter einer übersprungenen Uhr (und druckt Daten in der Vergangenheit). Entscheide nur aus Spalten, die die Maschine geschrieben hat, und hänge verwandte Daten an einen gespeicherten Anker.

Schritt 4 – Text für einen Sperrbildschirm

Eine Datei enthält jeden ausgehenden String.

  • Keine Emojis, keine Ausrufezeichen, kein Marketing.
  • Niemals ein nackter Wochentag für ein Datum, das mehr als einen oder zwei Tage entfernt ist. Sun Aug 30.
  • Vergib Zeichensetzung und Groß-/Kleinschreibung bei jedem Schlüsselwort – Wait. und Yes! müssen ankommen.
  • Prosa, die ein Schlüsselwort enthält, ist immer noch Prosa: „we should wait and see“ ist nicht WAIT. Vergleiche die gesamte kanonisierte Nachricht, niemals eine Teilzeichenfolge.
  • STOP / HELP / START werden vor dem gesamten Anwendungszustand und vor jedem Modellaufruf geparst, damit ein Opt-out nicht durch einen Fehler woanders oder einen API-Ausfall unterbrochen werden kann.
  • Wenn ein Modell Inhalte überwacht, schließe bei Fehler ab: wenn die Prüfung nicht ausgeführt werden kann, sende nichts und sag es.

Schritt 5 – wenn ein Modell Benutzerinhalte umschreibt, führe es aus, bevor du ihm vertraust

Ein Wächter, der Drittanbieternamen aus Benutzereinträgen entfernt, kann perfekt lesen und trotzdem:

  1. Eine Tatsache erfinden – gebeten, „Jane Doe“ durch „einen natürlichen Handle“ zu ersetzen, schrieb es „das Mädchen aus der App“, obwohl nichts eine App erwähnte; Empfänger lasen eine Erfindung als Tatsache.
  2. Überkorrigieren und echte Details löschen – „Jane vom Laufclub“ wurde zu „ihr“.

Regel: Die Anweisung muss sagen, was das Modell NICHT erfinden darf und was es NICHT löschen darf. Die funktionierende Form: Verankere die Ersetzung in der Quelle, ersetze das Token, nicht die Phrase darum herum, und bevorzuge einen neutralen Fallback gegenüber der Wiederverwendung eines Details, das der Satz bereits angibt.

Regel: Pinne jeden Live-Modell-Fehler als einen Opt-in-Test, der ohne API-Schlüssel übersprungen wird, damit Prompt-Änderungen sie nicht stillschweigend verschlechtern können, ohne bei jedem Testlauf Kosten zu verursachen. Budgetiere 2-5s pro Wächteraufruf.

Kosten (Größenordnung; live bestätigen)

Eine +1-Langcode kostet ein oder zwei Dollar pro Monat; SMS unter einem Cent pro Segment pro Richtung; MMS ein paar Cent. Die Einzelunternehmer-Registrierung kostet ein paar Dollar einmalig plus eine kleine monatliche Kampagnengebühr. Telegram ist kostenlos.

Fragen vs. Entscheidungen

  • Fragen: ob man eine ehrliche Registrierung einreicht, wohlwissend, dass sie dauerhaft abgelehnt werden könnte, oder auf Telegram startet (Geld und ein irreversibles Ergebnis); alles, was das Wesen des Produkts ändert.
  • Entscheiden: Architektur, Textstimme, die Zustandsmaschine, Testabdeckung, welcher Adapter zuerst, Datumsformate, Wächterverhalten.

Bevor du etwas als blockiert meldest, zähle jeden möglichen Berechtigungsnachweis auf (ein erschöpfter API-Schlüssel auf der Festplatte bedeutet nicht, dass es nicht einen anderen gibt, der funktioniert).

Siehe auch: build-remote-mcp-server (ein weiteres „natives Oberflächen“-Muster).

Individual skills in this repo

This repo contains 7 individual skills — each has its own dedicated page.

2016judea/ascii-charts

Build charts as plain Unicode-block text — bar, range, bullet, gap-bracket, star-histogram, heatmap, line, Venn, pie, donut and scatter — with a dependency-free Python script, for anywhere only monospace text survives (newsletter code blocks, Markdown, terminals, plain-text email, chat). Use when a chart has to embed as literal text instead of an image or a third-party chart service, or when you want a hand-made terminal look with no branding footer.

2016judea/buffett-checklist

Apply Warren Buffett's investment framework as a discipline lens when weighing a buy, hold, or sell decision — circle of competence, economic moat, owner earnings & intrinsic value, margin of safety, management/capital-allocation quality, and market psychology (Mr. Market, fear vs greed, temperament). Use when asked to "run this through Buffett", "what would Buffett say", "does this pass the moat test", "is this cheap enough", or for a second, more skeptical read on a name being evaluated or already held. This is a discipline overlay, not a replacement for a strategy — it applies the Buffett lens to how someone actually invests, rather than issuing generic advice.

2016judea/image-riff

Turn one or more reference images into original art in that reference's own visual language, then cut it to whatever surface it's for. Use when you paste or point at art and say "use this as the base image", "generate art from this", "riff on this", "some creative ideation with these images", "make me a channel banner / avatar / cover / plate", "wilder version of this", or want a spread of options off one piece of reference. This is the TASK skill; the engine is the `make-art` tool skill.

2016judea/leonardo

Draw the way Leonardo da Vinci drew — a study sheet, a notebook folio, a red-chalk or silverpoint study, a machine cutaway, a storm of vortices — in his real materials and page-logic, generated with the make-art engine and anchored on fifteen of his actual (public-domain) sheets. Use when you say "Leonardo", "da Vinci", "like his notebooks", "a codex page of X", "draw this as one of his study sheets", "sanguine", "silverpoint", or wants a design, diagram, or illustration in that hand. Also a reading guide to his notebooks (Richter's 1883 public-domain translation) for "what did Leonardo say about shadow / trees / water". This is a TASK skill; the engine is `make-art`.

2016judea/mcp-stack

Which free MCP server or framework to reach for, and its traps — finance/gov data (SEC EDGAR, Yahoo, SAM.gov, USAspending), web research (Exa, Firecrawl, Crawl4AI, Jina reader), design/art/brand (Canva, Inkscape, Penpot, Figma, Orshot, Hugging Face image gen, vectorizing, charts), data/spatial (DuckDB spatial, live ArcGIS layers, OpenStreetMap/Overpass, Census, MapLibre), and ops (PostHog, iMessage, context7 docs). Use when making a social post, OG card, poster, logo/vector, chart, map, or brand asset; when querying parquet/geojson/duckdb or a city's open-data layer; when an MCP "needs authentication" or fails; or when asked "what tools do we have", "is there an MCP for X", "should we add X".

2016judea/records-request

Get a specific record out of a US government office by public-records request — "request the assessor's model", "file a data practices request", "FOIA this", "open records request", "can we just ask the county for it", "who do I write to at <county>", "chase that request", "did they ever answer". Covers checking the website first, finding the right office and statute, the carve-out paragraph that makes a request answerable instead of refused, web-form traps (hidden character caps, WAFs that reject apostrophes), chasing (there is usually no deadline), whether what comes back may be republished, and parsing multi-year tables without silent errors.

2016judea/vertical-market-agent

Build a chat agent that knows one industry in one metro better than any general model because it carries a precomputed digest of real public records (or a mined review corpus) and can pull live records mid-conversation — finding the moat, building a byte-stable substrate, enumerating what the records can't, the data traps that produce plausible wrong numbers, deterministic math in tools, measured prompt cost and cache TTL, shipping as an ad destination, an off-sector ending, and a precomputed spatial "what is this next to" layer. Use when building a vertical AI agent grounded in records rather than general knowledge.

Verwandte Skills