Get Bananas
iPhone、iPad、Mac、Apple Watch向けの手書き風買い物リスト。両手がふさがっているときでも、Claudeが代わりに編集してくれます。
2026年4月リリース。すべてのデバイスでSwiftUI。MacアプリにはClaude Desktop拡張を内包。29言語に対応し、それぞれに手作業でキュレーションした初期データを用意したので、ユーザーが最初に目にするリストは「翻訳されたもの」ではなく「現地のもの」として読めます。サーバーなし、アカウントなし、APIキーなし。バックエンドはあなたのiCloudコンテナ内にあるJSONファイル1つだけです。
Claudeが、あなたの買い物リストを書き換えられる。
Get Bananasは、Claude Desktop拡張をMacアプリそのものに同梱しています。Macで設定を開き、拡張をインストールをクリックすると、Claude Desktopがインストール確認を表示します。承認して新しいチャットを開けば、Claudeはあなたの実際の買い物リストを読み書きできる5つのツールを手にしています。「リストには何がある?」と尋ねれば答えてくれます。「卵と牛乳を追加して」と言えば、次にiCloudが同期したときiPhoneに表示されます。
サインアップも、APIキーも、こちら側のサーバーもありません。拡張は.mcpb形式のバンドルで、Node.js製のMCPサーバーと通信し、そのサーバーがあなた自身のiCloud Driveコンテナ内のJSONファイル1つを読み書きします。
5つのツール、それぞれに1つの仕事。
ツールの構成は意図的に小さく抑えています。Claudeができるのは、リストを読む、項目を追加する、削除する、更新する、まるごと置き換える、これだけです。気の利いた便利ヘルパーも、read-modify-writeのラッパーもありません。会話で実際に依頼するであろう内容そのままが、ツールの形になっています。
- get_shopping_list現在のリストを読み取る
- add_item新しい項目を末尾に追加
- remove_item項目を1つ削除
- update_itemチェック、チェック解除、名前変更、数量の変更
- update_shopping_list丸ごと置き換える(例:「サンクスギビングのリストを始めて」)
アプリ内からインストール。
Macアプリの設定には「拡張をインストール」ボタンがあります。タップすると、アプリに同梱されたget-bananas.mcpbファイルがNSWorkspaceで開かれ、Claude Desktopが拡張として登録し、ユーザーに確認を求めます。インストール処理全体は、アプリバンドル内のファイルに対するNSWorkspace.shared.open()の1回呼び出しに収まっています。プラットフォーム側が「これを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風の手書き文字、区切り線にはペンの細い線、未チェックの項目には中空の丸。タップしてチェックを付けると、アプリが文字に手描きの線を引きます。そして、その線は1本ごとに少しずつ違います。




取り消し線は<code>Shape</code>で、すべてのチェックは唯一無二。
手描きの線は、20本のパスセグメントを持つカスタムSwiftUIのShapeです。各セグメントの端点には、-1.5から+1.5ポイントの間でランダムな垂直方向のオフセットを与えます。結果として、実行時に描画される取り消し線は、毎回ひとつ前のものとほんの少しだけ違います。20項目のリストを通しても、同じ線は2本とありません。本物のペンの線が決して同じにならないのと同じです。
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 } }
コードはたった12行。それでも、これは見た目が手書きのアプリと、触った感覚が手書きのアプリの違いです。静的なSVGの取り消し線でも同じ日に出荷でき、同じピクセル数で済んだでしょう。ただし、それは装飾としか映らなかったはずです。
上の2つのチェック済み項目をよく見てください。「Egg whites」と「Cottage cheese 2%」を貫く線は形が違います。揺れ方も違えば、角度も違う。同じShapeが200ミリ秒の間隔で、それぞれ新たな乱数を引きながら描いたものです。これがアプリのアイデンティティそのものです。小さく、嘘のない揺らぎを、レイアウトに焼き込むこと。
29言語、現地仕様の買い物データ付き。
日本人ユーザーが最初に開くリストは、アメリカ流の食料品リストを翻訳したものではありません。たんぱく質セクションに並ぶ卵白。東京の棚で実際に目にするであろう用語で書かれた、Proteinsセクションです。App Storeで29言語に対応し、英語以外の各ロケールには手作業でキュレーションしたSeedData-{locale}.jsonを同梱しました。文化的に適切なサンプル項目とセクション名が入っています。アラビア語ならal-burutinatにbiyad al-bayd。ヘブライ語ならhelbonimにhelbonei beitza。29個の初期データファイルは、文字列翻訳ツールに通したものではなく、すべて手書きで作成しました。





RTLは、抗うのをやめれば只でついてくる。
SwiftUIは.leadingと.trailingを「意味としての方向」として扱い、.leftや.rightのような固定の方向としては扱いません。一度セマンティックに画面をレイアウトしておけば、アラビア語とヘブライ語ではレイアウト全体が無料で反転します。セクション見出しは右に移り、チェック用の丸はテキストの左に移り、リセットボタンとMoreボタンは反対側のコーナーに回ります。RTL専用のコードは1行も書いていません。
手描きの取り消し線はそのすべての上に乗っていますが、ロケールを知る必要はありません。Shapeは項目名のTextの上に重ねたZStackに置かれ、そのテキストのバウンディングボックスを横切るように描画されます。周囲の行はSwiftUIのRTLレイアウトが鏡映しにしてくれます。線は、Shape側に言語ごとの分岐を一切書かなくても、本来あるべき場所——テキストの上——にきちんと収まります。
iCloudコンテナ内のJSONファイル1つ。
デバイス間のやり取りは、あなた自身のiCloud Drive内にあるたった1つのファイル——Get Bananasコンテナ内のBananaList.json——です。MCPサーバーはまさにこのファイルを読み書きします。iOS、iPad、Mac、Watchの各アプリも、まさにこのファイルを読み書きします。同期はiCloudが担当します。Appleの無料、保存時暗号化、Advanced Data Protectionが有効ならエンドツーエンドで非公開になるインフラです。私たちのインフラは何ひとつ介在していません。
// 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、アトミック書き込み、5秒のタイムアウトで放置されたら自動でクリア)、書き込みはプロセスIDタグ付きの一時ファイル(.tmp.{pid})に行ったうえで、本来のパスへアトミックにリネームします。Claudeと動作中のアプリのあいだの並行処理モデル全体は、acquire/releaseの関数1つに収まります。
各デバイスでは、ローカルストアはSwiftDataです。iCloud上のJSONはワイヤーフォーマットです。SwiftDataはデバイス上で高速かつクエリ可能なまま、JSONは同期用にも、Claudeが操作する用にもシンプルで人間が読める形のまま。2つのストア、それぞれ仕事は1つだけ。どちらも両方になろうとはしません。
これによって約束できること。
941 Appsのサーバーなし。アナリティクスなし。ログインなし。Claude用のAPIキーもなし——あなたはすでにClaude Desktopで認証済みです。サブスクリプションなし。拡張はオープンソースで、興味のある人はデータの通り道を最初から最後まで読めます。それはJSONファイルだけ、そしてそれが触れるすべてです。あなたの買い物リストは、こちらのインフラを介してiCloudコンテナの外に出ることが一切ありません。
仕事はリストそのもの。
買い物リストの仕事は1つです。思いついた瞬間に項目を捉え、見つけたらチェックを入れ、それ以外の時間はあなたの邪魔をせず引っ込んでいる。この仕事こそが製品です。レシピアプリでも、献立プランナーでも、バーコードスキャナーでも、価格トラッカーでも、在庫管理ツールでもありません。リストが、納品物です。
Claude統合がここに居場所を得ているのは、まさに「電話で打ち込むのが間違った道具になる場面」で、項目の追加と編集を加速させるからです。にんにくの匂いがする手でコンロの前に立っているとき、声に出して1週間の献立を相談しているとき、レシピカードの12項目を1つずつ打ち直さずに写し取りたいとき。そうした瞬間をClaudeに任せることで、アプリの残りの部分は小さいまま保てます。
リスト、追加、チェックオフ、そしてその委譲以外のものは、別の製品です。別の製品は、別のアプリが担うべきです。
Get Bananasに「ない」もの。
ほとんどの買い物リストアプリのロードマップは、最終的に「Instacartになる」で終わります。これは、そういうアプリではありません。Get Bananasは、意図的に食料品プラットフォームへ育つことを拒みます。「やらないこと」を明示します。
- バーコードスキャンなし
- 価格、合計、予算管理なし
- レシピのインポートや献立計画なし
- 通路ナビゲーションや店舗マップなし
- Webアプリなし
- アカウントなし、ログインなし、メール収集なし
- 他のユーザーとの共有リストなし(自分自身のiCloud内、自分のデバイス間でのみ)
- アナリティクスなし、未来永劫
- 広告なし、サブスクリプションなし、Proプランなし
- うるさい誘導表示なし、アプリ内アップセルなし
Get Bananasは0.99ドルです。一度払えばあなたのものです。MCPサーバーはオープンソース。データはあなたのもので、あなたのiCloud Driveに置かれます。仕事は素早い項目追加、素早いチェックオフ、そして両手がパクチーで埋まっているときに編集をClaudeへ委譲することだけ。それ以外は、すべて誰か別のアプリの仕事です。
Get Bananas.
iPhone、iPad、Mac、Apple Watch向けにApp Storeで配信中。Claude Desktop拡張はMacアプリ内からインストールできます。