Get Bananas

一份適用於 iPhone、iPad、Mac 與 Apple Watch 的手寫式購物清單——當你雙手忙著時,Claude 也能幫你編輯。

2026 年 4 月推出。每台裝置都用 SwiftUI 打造。Mac 應用程式內附 Claude Desktop 擴充功能。二十九種語言,每一種都搭配親手挑選的種子購物資料,讓使用者第一眼看到的清單感覺像在地原生,而非翻譯而來。沒有伺服器、沒有帳號、沒有 API 金鑰。整個後端就是你 iCloud 容器裡的一個 JSON 檔。

Get Bananas 在 iPhone 上顯示一份手寫風格的購物清單,列著蛋白質與碳水化合物
Claude Desktop
把香蕉加到我的購物清單
add_item({"name": "bananas"})
完成——已將香蕉加到「蔬果」分類。還需要其他項目嗎?
Claude 整合

Claude 可以更動你的購物清單。

Get Bananas 在 Mac 應用程式本身內部附帶一個 Claude Desktop 擴充功能。打開 Mac 上的「設定」,點選安裝擴充功能,Claude Desktop 就會跳出安裝提示。同意之後打開新對話,Claude 就有五個工具可以讀取並編輯你真實的購物清單。問它「我清單上有什麼?」——它會告訴你。說「加雞蛋和牛奶」——下次 iCloud 同步時,這些項目就會出現在你的 iPhone 上。

沒有註冊流程、沒有 API 金鑰、也沒有屬於我們的伺服器。這個擴充功能是一份 .mcpb 套件,與 Node.js MCP 伺服器溝通,讀寫的是你自己 iCloud Drive 容器裡的單一 JSON 檔案。

Claude Desktop 聊天畫面,使用者要求清空購物清單並加入一份生酮 Chipotle 墨西哥捲餅碗,Claude 正在呼叫 replace_shopping_list 工具
提出請求。 Claude 讀取現有清單,選擇 update_shopping_list,起草替換內容,並在任何變更套用前準備好呼叫。
Claude Desktop 聊天畫面顯示替換清單後的詳細烹飪備註:為了脂肪含量選雞腿肉而不是雞胸肉,選整顆花椰菜而不是預切米粒狀花椰菜,以及阿多波罐頭的用法
提出修正。 用整顆花椰菜,而不是預切花椰菜米。為了脂肪,選雞腿肉而不是雞胸肉。智慧不在資料庫裡,而在站在使用者和清單之間的模型裡。
Claude Desktop 你已安裝的應用程式
MCP 伺服器 get-bananas.mcpb
Get Bananas iCloud · BananaList.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」的檔案格式。

Mac 上的 Get Bananas 設定面板,顯示主題和語言選擇器
開啟設定。 主題、語言和 iCloud 同步介面。熟悉的 SwiftUI Form,以及依地區語言呈現的原生排版。
Mac 上的 Get Bananas 設定面板,顯示 Claude Desktop 區段和 Install Extension 按鈕
捲動到 Claude Desktop。 只有透過 LaunchServices 偵測到 Claude Desktop 時,Install Extension 按鈕才會出現。輕點一次,就會把內建的 .mcpb 註冊到 Claude。
Swift · SettingsView.swift:309-324
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 風格的手寫字體、分隔線是淡淡的鋼筆細線、未勾選項目是空心圓圈。當你輕觸勾選某個項目時,應用程式會在文字上畫一條手繪線——而每一條線都略有不同。

Get Bananas 在 iPhone 上顯示購物清單
iPhone
Get Bananas 在 iPad 上顯示購物清單
iPad
Get Bananas 在 Apple Watch 上顯示購物清單
Watch
Get Bananas 在 Mac 上顯示購物清單,搭配手繪風格標題
Mac

刪除線是一個 <code>Shape</code>,每一個勾選都是獨一無二的。

這條手繪線是一個自訂的 SwiftUI Shape,由二十段路徑組成。每段端點都會在 -1.5 到 +1.5 點之間取得一個微小的隨機垂直偏移。結果是:每一條在執行階段繪製的刪除線,都和上一條略有差異。在一份二十項的清單裡,沒有兩條線會完全相同——就像沒有兩筆筆觸會一模一樣。

Swift · HandDrawnStrikethrough.swift
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 刪除線同樣能在當天交付,像素數一樣,但會被當成裝飾。

Get Bananas 在 Mac 上顯示兩個已勾選項目,配上手繪刪除線,每一條都略有不同
兩條刪除線・兩條截然不同的線

仔細看看上方那兩個已勾選的項目。穿越「Egg whites」與「Cottage cheese 2%」的線條形狀並不一樣——晃動不同、角度也不同。它們是同一個 Shape 在相距 200 毫秒間生成的,每次都重新抽取隨機性。這就是這款應用程式的整體性格:細小、誠實的變化,內建在版面之中。

在地化

二十九種語言,附在地購物資料。

日本使用者第一次打開的清單,並不是翻譯過來的美式雜貨採購。它是たんぱく質分類裡的卵白——也就是蛋白,放在你真的會在東京貨架上看到的「蛋白質」分類底下。App Store 上有二十九種在地化版本,每個非英文語系都附上自己親手挑選的 SeedData-{locale}.json,內含符合當地文化的範例項目與分類名稱。阿拉伯文版本是 al-burutinat 分類裡的 biyad al-bayd。希伯來文版本是 helbonim 分類裡的 helbonei beitza。二十九份種子檔案,全靠手寫,不是丟進字串翻譯器跑一次就交差。

Get Bananas 英文版顯示蛋白質區塊,包含蛋白、茅屋起司、雞胸肉
EnglishProteins · 預設種子資料
Get Bananas 日文版以片假名與漢字顯示在地食材名稱
日本語たんぱく質 · 在地種子資料
Get Bananas 阿拉伯文版顯示由右至左的版面與在地食材名稱
العربيةالبروتينات · RTL
Get Bananas 希伯來文版顯示由右至左的版面與在地食材名稱
עבריתחלבונים · RTL
Get Bananas 簡體中文版顯示在地食材名稱
简体中文蛋白质 · 在地種子資料

只要不去抗拒它,RTL 就是免費的勝利。

SwiftUI 把 .leading.trailing 視為語意上的方向,而不是 .left.right 那種固定方位。只要在語意層面把畫面擺好一次,阿拉伯文與希伯來文就會免費自動翻轉整個版面——分類標題換到右邊、勾選圓圈換到文字左邊、「重設」與「更多」按鈕也會旋轉到對角。我們完全沒有為此寫一行 RTL 專屬的程式碼。

Get Bananas 英文版有兩個已勾選項目,由左至右版面
英文 · LTR
Get Bananas 阿拉伯文版有兩個已勾選項目,由右至左版面
阿拉伯文 · RTL
Get Bananas 希伯來文版有兩個已勾選項目,由右至左版面
希伯來文 · RTL

手繪刪除線就疊在這一切之上,根本不需要知道目前的語系。Shape 放在項目名稱 Text 上方的 ZStack 裡,在那個邊界框中繪製;周圍那一行是由 SwiftUI 的 RTL 版面負責鏡像翻轉。線條最終會落在它該去的地方——在文字之上——而 Shape 程式碼裡完全沒有任何語言相關的判斷。

架構

你 iCloud 容器裡的一個 JSON 檔。

跨裝置交換的內容就是你自己 iCloud Drive 裡的單一檔案:Get Bananas 容器中的 BananaList.json。MCP 伺服器讀寫的就是這個檔。iOS、iPad、Mac 與 Watch 應用程式讀寫的也是這個檔。iCloud 負責同步——這是 Apple 提供的免費基礎設施,靜態加密,當「進階資料保護」啟用時更是端對端私密。我們什麼都沒有。

JavaScript · mcp-extension/server/index.js:21-28
// 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 擴充功能。