Get Bananas
一份適用於 iPhone、iPad、Mac 與 Apple Watch 的手寫式購物清單——當你雙手忙著時,Claude 也能幫你編輯。
2026 年 4 月推出。每台裝置都用 SwiftUI 打造。Mac 應用程式內附 Claude Desktop 擴充功能。二十九種語言,每一種都搭配親手挑選的種子購物資料,讓使用者第一眼看到的清單感覺像在地原生,而非翻譯而來。沒有伺服器、沒有帳號、沒有 API 金鑰。整個後端就是你 iCloud 容器裡的一個 JSON 檔。
Claude 可以更動你的購物清單。
Get Bananas 在 Mac 應用程式本身內部附帶一個 Claude Desktop 擴充功能。打開 Mac 上的「設定」,點選安裝擴充功能,Claude Desktop 就會跳出安裝提示。同意之後打開新對話,Claude 就有五個工具可以讀取並編輯你真實的購物清單。問它「我清單上有什麼?」——它會告訴你。說「加雞蛋和牛奶」——下次 iCloud 同步時,這些項目就會出現在你的 iPhone 上。
沒有註冊流程、沒有 API 金鑰、也沒有屬於我們的伺服器。這個擴充功能是一份 .mcpb 套件,與 Node.js MCP 伺服器溝通,讀寫的是你自己 iCloud Drive 容器裡的單一 JSON 檔案。
五個工具,各司一職。
工具介面刻意保持精簡。Claude 可以讀取清單、新增項目、移除項目、更新項目,或整份替換。沒有花俏的便利助手,也沒有讀取-修改-寫入的包裝層;介面就只反映你會在對話中真正提出的需求。
- get_shopping_list讀取目前的清單
- add_item新增一個項目
- remove_item移除單一項目
- update_item勾選、取消勾選、重新命名或變更數量
- update_shopping_list整份替換(例如「開始一份感恩節清單」)
從應用程式內部安裝。
Mac 應用程式的「設定」裡有一個「安裝擴充功能」按鈕。點下去會用 NSWorkspace 開啟內附的 get-bananas.mcpb 檔案,Claude Desktop 就會將它註冊為擴充功能並請使用者確認。整個安裝過程其實只是對應用程式套件內檔案執行一次 NSWorkspace.shared.open()——因為平台已經提供了正確的基本工具:一種代表「將我註冊到 Claude」的檔案格式。
private func installExtension() { guard let extensionURL = Bundle.main.url( forResource: "get-bananas", withExtension: "mcpb" ) else { extensionMessage = "Error: Extension not found in app bundle." return } let opened = NSWorkspace.shared.open(extensionURL) if opened { extensionMessage = "Check Claude Desktop for the install prompt..." } else { extensionMessage = "Couldn't open the extension. Make sure Claude Desktop is installed." } }
這套模式對許多原生應用程式都將至關重要。擴充功能就住在你的應用程式套件裡,跟著應用程式一起發行、一起更新——沒有獨立註冊表、沒有逐個使用者的設定、也不必「把這個 URL 複製到設定檔裡」。如果你希望 Claude 能在你的應用程式裡做某件事,就把那件事放進應用程式裡,讓 OS 來居中介紹。
紙上鋼筆,加上記憶。
購物清單就是用筆、寫在紙上、靠手親自完成的。這款應用程式就是這種感覺。分類標題使用 Caveat 風格的手寫字體、分隔線是淡淡的鋼筆細線、未勾選項目是空心圓圈。當你輕觸勾選某個項目時,應用程式會在文字上畫一條手繪線——而每一條線都略有不同。




刪除線是一個 <code>Shape</code>,每一個勾選都是獨一無二的。
這條手繪線是一個自訂的 SwiftUI Shape,由二十段路徑組成。每段端點都會在 -1.5 到 +1.5 點之間取得一個微小的隨機垂直偏移。結果是:每一條在執行階段繪製的刪除線,都和上一條略有差異。在一份二十項的清單裡,沒有兩條線會完全相同——就像沒有兩筆筆觸會一模一樣。
struct HandDrawnStrikethrough: Shape { func path(in rect: CGRect) -> Path { var path = Path() let startY = rect.midY let segments = 20 let segmentWidth = rect.width / CGFloat(segments) path.move(to: CGPoint(x: 0, y: startY)) for i in 1...segments { let x = CGFloat(i) * segmentWidth let randomOffset = CGFloat.random(in: -1.5...1.5) let y = startY + randomOffset path.addLine(to: CGPoint(x: x, y: y)) } return path } }
這只是十二行程式碼。但這也就是「看起來像手寫的」與「感覺像手寫的」之間的差別。一個靜態 SVG 刪除線同樣能在當天交付,像素數一樣,但會被當成裝飾。
仔細看看上方那兩個已勾選的項目。穿越「Egg whites」與「Cottage cheese 2%」的線條形狀並不一樣——晃動不同、角度也不同。它們是同一個 Shape 在相距 200 毫秒間生成的,每次都重新抽取隨機性。這就是這款應用程式的整體性格:細小、誠實的變化,內建在版面之中。
二十九種語言,附在地購物資料。
日本使用者第一次打開的清單,並不是翻譯過來的美式雜貨採購。它是たんぱく質分類裡的卵白——也就是蛋白,放在你真的會在東京貨架上看到的「蛋白質」分類底下。App Store 上有二十九種在地化版本,每個非英文語系都附上自己親手挑選的 SeedData-{locale}.json,內含符合當地文化的範例項目與分類名稱。阿拉伯文版本是 al-burutinat 分類裡的 biyad al-bayd。希伯來文版本是 helbonim 分類裡的 helbonei beitza。二十九份種子檔案,全靠手寫,不是丟進字串翻譯器跑一次就交差。





只要不去抗拒它,RTL 就是免費的勝利。
SwiftUI 把 .leading 與 .trailing 視為語意上的方向,而不是 .left 與 .right 那種固定方位。只要在語意層面把畫面擺好一次,阿拉伯文與希伯來文就會免費自動翻轉整個版面——分類標題換到右邊、勾選圓圈換到文字左邊、「重設」與「更多」按鈕也會旋轉到對角。我們完全沒有為此寫一行 RTL 專屬的程式碼。
手繪刪除線就疊在這一切之上,根本不需要知道目前的語系。Shape 放在項目名稱 Text 上方的 ZStack 裡,在那個邊界框中繪製;周圍那一行是由 SwiftUI 的 RTL 版面負責鏡像翻轉。線條最終會落在它該去的地方——在文字之上——而 Shape 程式碼裡完全沒有任何語言相關的判斷。
你 iCloud 容器裡的一個 JSON 檔。
跨裝置交換的內容就是你自己 iCloud Drive 裡的單一檔案:Get Bananas 容器中的 BananaList.json。MCP 伺服器讀寫的就是這個檔。iOS、iPad、Mac 與 Watch 應用程式讀寫的也是這個檔。iCloud 負責同步——這是 Apple 提供的免費基礎設施,靜態加密,當「進階資料保護」啟用時更是端對端私密。我們什麼都沒有。
// iCloud path for Banana List data const ICLOUD_FILE_PATH = path.join( os.homedir(), "Library/Mobile Documents/iCloud~com~941apps~Banana-List/Documents/BananaList.json" ); // Lock file for atomic operations const LOCK_FILE_PATH = ICLOUD_FILE_PATH + ".lock"; const LOCK_TIMEOUT_MS = 5000;
MCP 伺服器接觸到的每一條路徑,都是那個 JSON 檔的兄弟檔。鎖定檔就放在它旁邊(.lock,原子寫入,五秒逾時且若過期會自動清理)。寫入會先寫到帶有行程標記的暫存檔(.tmp.{pid}),再原子化重新命名為正式路徑。整個並行控制模型——Claude vs. 執行中的應用程式——可以用一個取得/釋放函式裝完。
在每台裝置上,SwiftData 是本地儲存層。iCloud 上的 JSON 才是傳輸格式。SwiftData 在裝置上保持快速且可查詢;JSON 則保持簡單可讀,方便同步、也方便 Claude 操作。兩個儲存層各做一件事——誰都不嘗試一人兼任兩職。
這讓我們敢於做出哪些承諾。
沒有 941 Apps 伺服器。沒有分析。沒有登入。沒有給 Claude 用的 API 金鑰——你已經在 Claude Desktop 完成驗證了。沒有訂閱。擴充功能完全開源,任何好奇的人都能讀完整條資料路徑:就是那個 JSON 檔,它從頭到尾就只碰那一個檔。你的購物清單從不透過任何屬於我們的基礎設施離開你的 iCloud 容器。
工作就是那份清單。
購物清單就是一份工作。在你想到某項東西的當下捕捉下來、找到它時打勾、其他時間就讓清單退到一旁別擋路。產品本身就是那份工作。它不是食譜應用程式、不是備餐規劃器、不是條碼掃描器、不是價格追蹤器、也不是庫存管理工具。清單,才是交付物。
Claude 整合之所以值得擁有一席之地,正因為它在「拿手機打字是錯誤工具」的場景中,加速了輸入與編輯:站在爐邊雙手沾滿大蒜味、邊聊邊規劃這週的餐點、把食譜卡上十二項東西照抄而不必逐一重打。把這些片刻交給 Claude,能讓應用程式的其他部分維持精簡。
凡是不屬於清單、輸入、勾選或那種委派的事情,都是另一款不同的產品。不同的產品該歸不同的應用程式。
Get Bananas 裡沒有的東西。
多數購物清單應用程式的路線圖最終都通往「變成另一個 Instacart」。這款不是。Get Bananas 是刻意拒絕長成一個雜貨平台的。以下是它明確不做的事:
- 沒有條碼掃描
- 沒有價格、總計或預算功能
- 沒有食譜匯入或備餐規劃
- 沒有走道導引或商店地圖
- 沒有網頁版
- 沒有帳號、沒有登入、不蒐集電子郵件
- 沒有與其他使用者共享清單(只有你自己的 iCloud,跨你自己的裝置)
- 永遠沒有任何分析
- 沒有廣告、沒有訂閱、沒有 Pro 方案
- 沒有惱人的提示視窗,也沒有應用程式內推銷
Get Bananas 售價 $0.99。買斷一次就是你的。MCP 伺服器是開源的。資料屬於你自己,住在你的 iCloud Drive。它的工作就是快速輸入、快速勾選,以及在你雙手沾滿香菜時把編輯交給 Claude。除此之外的一切,都是別人家的應用程式。
Get Bananas.
iPhone、iPad、Mac 與 Apple Watch 版本現已在 App Store 上架。從 Mac 應用程式內安裝 Claude Desktop 擴充功能。