Community生產力與協作github.com

2016judea/sms-native-product

建立一個以簡訊而非應用程式或網站為介面的產品——「無應用程式、無網站」、「他們只需傳簡訊到一個號碼」、「以簡訊原生方式與我們的客服聊天」、「可以透過簡訊處理嗎」、「一個簡訊機器人」、「一個Telegram機器人」、「讓它變成群組聊天」、「最低摩擦」。同樣適用於已出錯的情況——「我的活動被拒絕了」、「我們的號碼被封鎖了」、「簡訊送達不到」、「為什麼我需要註冊」。涵蓋決定此類產品能否發送簡訊的關卡(美國A2P 10DLC註冊、SHAFT內容規則、永久拒絕代碼)、透過程式碼進行群組MMS、每個頻道的限制、能承受頻道遺失的架構,以及保護由模型改寫的使用者內容。

sms-native-product 是什麼?

這個技能指導開發者如何建立以簡訊(SMS)或其他訊息平台(如Telegram)為主要介面的產品,而不是傳統的應用程式或網站。它強調一個關鍵前提:在美國,電信業者嚴格控管A2P(應用程式對個人)簡訊流量,產品設計必須在第一步就應對註冊與內容審查(SHAFT規則),否則可能被永久拒絕。技能詳細說明了如何處理常見的註冊錯誤代碼(如30953、30885、30898),並給出審慎的商業建議,例如為附屬專案使用「獨資經營者」品牌以避免影響主業務。 技能的核心是提供一個可測試、可替換頻道的架構設計。它推薦將決策核心(state machine)與I/O完全分離,使邏輯可在模擬器中測試,而真實的通道(如Twilio、Telegram)則作為可互換的配接器。此外,它涵蓋了群組MMS的限制、Telegram機器人無法建立群組的事實、以及如何處理使用者內容的模型改寫,包括防止模型虛構事實或過度刪除細節的具體規則。 對於開發者來說,這個技能在於揭露了「純簡訊產品」背後的複雜現實:您不擁有頻道,因此架構必須能承受頻道遺失的風險。它提供了從註冊閘門、資料模型、測試策略到文案撰寫的完整實戰指南,幫助您避開常見的陷阱,例如合併不同的時間延遲物件、使用未經註冊的登陸頁面誤導審查、或是忽略頻道的技術限制。技能也強調了在回覆中明確命名產品內容類別的重要性,並在第一次回覆中就判斷該類別是否觸及拒絕規則,這會從根本上改變架構、登陸頁面文案和備援計畫。

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

Installed? Explore more 生產力與協作 skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

以簡訊為介面的產品

這個訴求很真實:人們不喜歡安裝應用程式或瀏覽網站,但每個人都會傳簡訊。問題是:你並不擁有這個頻道。 美國的電信業者擁有,他們有內容政策和審批流程,可以永久拒絕你。這個關卡決定了產品被允許成為什麼樣子,所以必須優先處理。


第零步 —— 關卡。在設計之前就做,而不是之後。

自 2025 年 2 月起,美國電信業者直接封鎖未註冊的 A2P 流量,因此品牌和行銷活動必須在發送第一則簡訊之前獲得批准。每次都要重新閱讀最新的錯誤文件;電信業者政策會變動。

代碼觸發條件可重新提交?
30953露骨/暗示性語言,或連結的網站包含「色情、交友、約會或成人娛樂內容」否
30885「高風險」— 欺騙性行銷,或註冊時虛報流量類型否
30898同一個 EIN 下註冊太多品牌,或註冊看起來重複是,有正當理由

規則:在第一次回覆中明確說出產品的內容類別,並說明它是否在那個清單上。 如果這個類別(例如約會)恰好是拒絕規則中的關鍵字,那麼在第五分鐘就發現它,會改變架構、登陸頁面文案和備援計畫。SHAFT 是速記法:性、仇恨、酒精、槍械、菸草——再加上大麻,而約會也緊跟在旁。

規則:將附屬專案註冊為「獨資經營者」品牌,而非放在現有公司的 EIN 之下。 風險模式會跟著稅號(30898)跑,所以附屬專案被拒絕不能影響你主要業務的發送能力。「獨資經營者」的範圍是沒有稅號的個人;吞吐量很低,但對測試版來說已經足夠。

規則:絕不要為了讓行銷活動通過審查而建立一個誘餌登陸頁面。 一個隱瞞實際流量的頁面就是 30885 模式,它會把一個號碼的風險轉變為你所有已註冊號碼的風險。直接陳述成功機率,讓負責人決定。

用機械性的行為來描述服務,而且只有在描述為真時才這樣做(例如日記和小組問責,當這就是訊息內容時)。如果沒有真實的描述能通過審查關卡,答案就是改用其他頻道,而不是找一個更好的委婉說法。

審查會獎勵那些可以指向的事實:僅接收的選擇加入、對話式的流量、重複訊息中沒有連結、優先處理 STOP 指令、在入口處拒絕露骨內容。

第零點五步 —— 閱讀需求摘要時要找「數字」和「物件」,而不是意圖

將創辦人的需求摘要一字不差地保留為 README.md,並在 CLAUDE.md 中說明它凌駕於所有工程文件之上。

規則:在編寫狀態機之前,列出摘要中的每個持續時間以及它作用於的每個名詞。如果有兩個持續時間,那就是兩個功能。 一份需求摘要中,對朋友回覆送達作者 有一週的延遲,而對作者自己的更新 有兩週的鎖定,很容易被合併成對條目 的七天保留——而這個條目並非兩個延遲所針對的物件——後續的每一個錯誤都源於這個合併。

規則:命名每個延遲的物件——「對誰保持『擱置』」。 對朋友保持擱置和對作者保持擱置是兩種相反的產品。

規則:當頻道無法強制執行需求摘要中的字面設計時,直接說出來並給出替代方案——不要默默地選擇可強制執行的方案。(群組聊天的建立者同時也是其成員,所以沒有程式碼可以對他們隱藏群組的回覆。)這是一個前提決策,而前提決策屬於產品負責人。

一個連貫的誤讀不會讓人感覺像誤讀。 保留已被取代的設計段落,並加上刪除線,而不是將其刪除;這可以讓後續的會話知道需求摘要如何被誤讀。

第一步 —— 頻道能做些什麼和不能做些什麼

  • 從程式碼進行群組簡訊是可行的。 Twilio Conversations 僅在 +1 長碼上支援群組 MMS——不支援免付費電話、不支援短碼——限制為包含你自己號碼在內最多 10 位參與者。不要憑記憶做出相反的斷言。
  • 群組 MMS 的 SMS 參與者帶有 Address 而沒有 ProxyAddress,因此一個號碼可以服務所有聊天室——但參與者/代理唯一性規則(50425)對於沒有代理的參與者沒有記錄的行為。絕對不要設計許多共用一個號碼和一組參與者的並發聊天室。 每人一個持久聊天室具有穩定的參與者集合。
  • 網頁無法讀取 iPhone 的通訊錄。 Contact Picker API 僅限 Chrome on Android。「同步你的聯絡人」從一開始就不可行;用一個使用者轉發的連結來取代它——接收者的傳入簡訊就是電信業者想要的同意記錄。
  • Telegram 機器人無法建立群組或將任何人加入群組,且在隱私模式下它只聽取發送給它的指令。這兩點都有幫助:建立者將機器人加入他們已有的聊天室,而一般聊天內容不會被誤認為輸入。建立機器人需要在 @BotFather 中由真人操作(沒有 API);索取 token。
  • WhatsApp Cloud API 沒有群組訊息功能。
  • iMessage API(Sendblue、LoopMessage)可以實現藍色泡泡和真實群組聊天,但每個號碼每月大約花費 100 美元,加上設置費。

第二步 —— 能承受頻道遺失的架構

因為頻道可能被拒絕,傳輸層必須是一個檔案:

machine.js   純函數:(context, event) -> {replies, effects}   無 I/O,無時鐘
engine.js    上下文組裝 -> machine -> effects                 完整路徑
effects.js   createEffects({db, channel})                     執行決策
twilio.js  / telegram.js                                      可互換
api/*.js     包覆 engine.js 的薄層                           ~10 行程式碼
sim/         記憶體資料庫 + 控制台頻道
  • 決策核心將 now 作為參數,且不接觸網路。 這類產品的每個錯誤都是時序錯誤(重複觸發的提醒、發送給空聊天室的訊息、從未送達的擱置項目),而且這些錯誤都無法在真實網路和七天計時器上進行測試。
  • 配接器在效果層中是參數,而非匯入——這正是模擬器和備援頻道所需的相同重構。
  • HTTP 處理程式中不能包含邏輯。 寫在 api/telegram.js 中的頻道特定引導流程是無法測試的;將其提取出來。

第三步 —— 驅動它,而不僅僅是測試它

node sim/drive.js          指令碼:完整循環,跳過一週,檢查守衛條件
node sim/drive.js --repl   以任何號碼輸入;/as <n>  /jump <days>  /state
  • 模擬器必須執行生產路徑,而不是一個並行的副本。
  • 預期第一次驅動會發現幾個單元測試無法達到的真實缺陷:一個聊天室在成員加入之前就向自己打招呼;一個是裸露的星期幾而非一週後的日期;一個提醒沒有說明它指的是哪個項目;一個聊天室的成員全部離開了。
  • 當測試失敗時,先檢查測試本身(一個日期正則表達式不允許 Sun, Aug 30 中的逗號;一個 doesNotMatch 錯誤地觸發於另一個合法的訊息)。
  • 絕不要根據資料庫儲存的時間戳來做決策或列印資訊。 資料庫從真實時鐘寫入 created_at,而不是來自引擎注入的 now,因此在跳過時鐘的情況下它會說謊(並列印出過去的日期)。只根據機器寫入的欄位來做決策,並將相關日期掛在一個儲存的錨點上。

第四步 —— 適合鎖定螢幕的文案

一個檔案存放所有對外輸出的字串。

  • 沒有表情符號、沒有驚嘆號、沒有行銷用語。
  • 對於超過一兩天後的日期,絕不要使用裸露的星期幾。 例如 Sun Aug 30。
  • 對每個關鍵字都容許標點符號和大小寫錯誤——Wait. 和 Yes! 都必須能匹配成功。
  • 包含關鍵字的散文仍然是散文:「we should wait and see」不是 WAIT。匹配整個規範化後的訊息,絕不匹配子字串。
  • STOP / HELP / START 在所有應用程式狀態和任何模型呼叫之前被解析,這樣退出功能就不會因為其他地方有錯誤或 API 故障而失效。
  • 如果模型負責把關內容,失敗時應關閉保護:如果檢查無法執行,則不發送任何內容並告知使用者。

第五步 —— 如果模型改寫使用者內容,在信任它之前先執行檢查

一個從使用者條目中移除第三方姓名的守衛可能讀起來完美,但仍然會:

  1. 虛構一個事實——被要求將「Jane Doe」替換為「一個自然的代稱」,它寫出了「應用程式裡的那個女孩」,但原文完全沒提到應用程式;接收者會將虛構內容視為事實。
  2. 過度修正並刪除真實細節——「跑步俱樂部的 Jane」變成了「她」。

規則:指令必須說明模型「不得」虛構什麼以及「不得」刪除什麼。 可行的形式:將替換建立在來源的基礎上,替換符號而非其周圍的片語,並且在重複使用句子已陳述的細節時,優先使用中性的備案。

規則:將每個線上模型的缺陷固定為可選測試,在沒有 API 金鑰的情況下跳過,這樣提示詞的修改就不會在每次測試運行中都無聲地回歸這些缺陷,同時增加成本。每次守衛呼叫預留 2-5 秒。

成本(數量級;需確認實際情況)

一個 +1 長碼每月大約一到兩美元;簡訊每段(雙向)不到一美分;MMS 幾美分。獨資經營者註冊是一次性幾美元加上少量月度行銷活動費用。Telegram 是免費的。

詢問 vs. 決定

  • **詢問:**是否要提交一份誠實但可能被永久拒絕的註冊,或者從 Telegram 開始(涉及金錢和不可逆的結果);任何會改變產品本質的事。
  • **決定:**架構、文案風格、狀態機、測試覆蓋率、先實作哪個配接器、日期格式、守衛行為。

在報告任何東西被封鎖之前,列舉每一個候選憑證(磁碟上一個用盡的 API 金鑰並不代表沒有另一個可用的)。

另見: build-remote-mcp-server(另一種「原生介面」模式)。

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.

相關技能