【一人ハッカソン】LocalSendが使えないHaiku OSのために、Claude Codeと4時間でLAN内P2Pファイル共有アプリを自作した話

みなさん、こんにちは。

最近ハッカソンに興味があって、近々どこかのイベントに参加してみたいなと考えています。ただ、2日制のハッカソンは正直集中力が持たない自信があるんですよね……。となると狙い目なのは1日完結型の超短期ハッカソンなのですが、そこで一番の壁になるのが「開発時間の圧倒的な不足」です。

そこで本番に向けたタイムマネジメントのリハーサルとして、8時間一本勝負の「一人ハッカソン(セルフハッカソン)」を決行することにしました!

最初の30分でテーマを決定。今回作るのは『LAN内爆速ファイル・テキスト共有ボード』です。


なぜ作るのか?(マイナーOSへのロマンと実用性)

実は以前もイベントでファイル共有に困ったことがあって、そのときの教訓からPythonの簡易HTTPサーバーを自作したことがあります。

参考:USBもクラウドも使えない!絶望的な状況を救うPythonの簡易HTTPサーバー

ただ、あらかじめ決まったファイルを配ることはできても、参加者同士でお互いに送受信できないのはちょっと致命的でした。

同じWi-Fi(LAN)に繋がっている端末同士でファイルやURLを共有するツールとしては、オープンソースの「LocalSend」が有名ですよね。すごく便利で私も愛用しています。

ですが、私が愛してやまないマイナーOS「Haiku OS」ではちょっと分が悪いのが現状です。以前試したBubiCamの作者であるatomozero氏によるネイティブクライアントは存在するものの、ビルドが必要だったりと導入のハードルは高いままなんですよね。

参考:atomozero/LocalSend

さらに、今後のハッカソン会場でチームメンバーと気軽にファイルやコードの切れ端を共有したいときに、サーバーにデータが残ってしまう仕組みや、重いアプリのインストールを強いるようなツールは使いたくありませんでした。また、インターネット接続が不安定な場合を想定して、ローカルだけで動く仕組みが絶対必要だと考えました。

それなら、「ブラウザさえあればOS不問で、サーバーにデータを1バイトも残さないP2Pの共有ツールを自作しちゃえばいいんじゃない?」と思い立ったわけです。

ターゲットはマイナーOSのHaiku OSから手元のスマホまで。なぜHaiku OSかというと、普段リモートデスクトップで作業する際にクリップボード経由のコピペができず、ずっと不便に感じていたからです。


開発環境と、今回の「秘密兵器」

今回の開発環境と挑戦的な技術スタックはこちらです。

  • 開発環境
    • WSL2 (Ubuntu 22.04)
  • 本番環境(デプロイ先)
    • Raspberry Pi (Raspbian Buster)
  • バックエンド
    • Python (FastAPI + WebSocket) ※接続の仲介(シグナリング)のみを担当し、DBやファイル保存は一切なし
  • フロントエンド
    • HTML + Vanilla JS + Tailwind CSS (CDN)
  • 通信方式
    • WebRTC (RTCPeerConnection / RTCDataChannel) による純粋なP2P転送

本番環境にRaspberry Piを選んだのは、最低限のリソースでもちゃんと動くものを作りたかったからです。実際のハッカソン当日は、おそらく手元のUbuntu環境で動かすことになると思います。

そして、このタイトな1日ハッカソンを共に戦う相棒(秘密兵器)として、ターミナル上で自律的にコードを生成・修正・実行してくれる最新のAI開発エージェント「Claude Code」を召喚しました。

Claude Code の使い方ですが、フロントエンドの実装迷子を完全に防ぐため、「最初にPythonでUIの完成予想図(デザイン画像)を生成させて、それをベースに実装を進める」というデザイン先行プロセスを採用しています。ちなみに、リポジトリ名は「WebSend」です。

果たして、Claude Codeと共に挑む8時間のタイムアタックで、ラズパイとHaiku OSを繋ぐP2Pアプリは無事に完成するのでしょうか……!?


まずは「作戦会議」- CLAUDE.mdとデザイン先行

いきなりコードを書かせるのではなく、最初にやったのは技術方針をまとめたCLAUDE.mdをClaude Codeに作ってもらうことでした。

  • サーバーにはWebRTCのシグナリング以外の役割を持たせない
  • フロントエンドはビルド不要の1ファイルにする
  • 機能は①シグナリング→②P2P接続→③ファイル・テキスト送受信の順に、小さく作って都度動かして確認する

この3つのルールを最初にしっかりすり合わせしておいたのが、後々かなり効いてくることになります。

続いてデザイン先行プロセスです。PythonのPillowでUIのモックアップ画像を生成してもらったのですが、ここでいきなり小さくつまずいてしまいました。生成されたdesign.pngを開いてみると、アイコンにしたつもりの絵文字が軒並み□(豆腐文字)になっていたんです。

原因を確認してみると「使用しているCJKフォントが絵文字グリフを持っていない」とのことでした。しかもHaiku OSのようなマイナー環境では、そもそも絵文字の表示自体が不安定になりがちです。そこで方針そのものを「絵文字は使わず、線画アイコンで表現する」に変更しました。地味なポイントですが、本番で困る前に見つけられたのは幸先が良かったですね。

モック画面
Claude Code で作ったモック画面

①→②→③、小さく作って、その場で動かす

CLAUDE.mdで決めた通り、機能は一気に作らず段階的に実装してもらいました。

  1. WebSocketシグナリング
    • ルームに参加すると、同じルームにいる他端末がリアルタイムに一覧へ表示されます。実装のたびに2つのブラウザタブを開いて実際に参加・離脱させ、目視で確認しました。
  2. P2P接続の確立
    • RTCPeerConnectionRTCDataChannelでofferとanswerをやり取りし、DataChannelがopenになったら簡単な「ハンドシェイク」メッセージを送り合う仕組みにしました。
  3. テキスト・ファイル送受信
    • ファイルは16KBずつのチャンクに分割して送信し、bufferedAmountを監視しながら詰まらないように調整。受信側はBlobを組み立てて自動ダウンロードさせます。

それぞれの機能ができるたびに、Claude Code自身にPlaywrightで自動テストを書かせて実際に2つのブラウザで動かし、送受信ログのスクリーンショットまで見せてもらってから次に進む――というサイクルを回していきました。これが後半の大トラブルでめちゃくちゃ役立つことになります。


まさかの伏兵、ラズパイのCPU

テーマ決定からわずか30分後には、本番環境であるRaspberry Pi 3B+(Raspbian Buster)に実際にデプロイしてテストする段階に入っていました。AIに伴走してもらうハッカソンは、全て人力だった頃とは時間感覚がまるで違いますね!以前ならここまでで数時間はかかっていたはずです。

ただ、ここからが本番でした。SSHでログインし、依存パッケージをインストールさせたところ……画面が固まったように動かなくなってしまいました。

調べてみると、uvicorn[standard]が引き連れてくるuvloopという高速化用の拡張が、非力なPi 3B+上でCソースからビルドされていたんです。gccが1コアを100%使い切っても終わる気配がありません。

  • uvicorn[standard](uvloopあり)
    ビルド開始から5分以上待っても完了せず、見切って中断
  • uvicorn(拡張なし)+websockets
    インストール完了まで数十秒

ハッカソン会場での少人数利用に、uvloopの速度最適化は正直オーバースペックですよね。非力な環境ではフル装備より身軽さが正義――頭では分かっていたつもりでしたが、実機で目の当たりにすると説得力が違いました。


実機テストで発覚した「接続できない」事件

さて、いよいよ本番さながらに複数の実機(Windows、Linux、Android、そしてHaiku OS)を集めて接続テストを行いました。ここで今日一番の事件が起きてしまいます。

同じルームの端末一覧には、お互いがちゃんと表示されている。なのに、Haiku OSだけがP2P接続の「接続」ボタンを押した瞬間に「接続失敗」になってしまうんです。

最初に疑ったのは、Wi-Fiルーターの「APアイソレーション」機能でした。同じWi-Fiでも端末同士の直接通信をブロックする設定って結構ありますよね。

次に疑ったのは、WebRTCのオブジェクトをそのままJSON.stringify()していたコードです。ブラウザの実装によってはRTCSessionDescriptionRTCIceCandidateのプロパティが「プロトタイプのgetter」になっていて、素直にJSON化すると中身が空の{}になってしまうことがあります。

さらに、Chrome系ブラウザはプライバシー保護のためWebRTCの接続先アドレスをxxxxxxxx-....localというmDNSの匿名ホスト名に隠してしまう挙動があり、これを解決できないブラウザからは相手の本当のIPアドレスが分からない可能性も出てきました。

そこでClaude Codeに、インターネットに出ずLAN内だけで完結する自前のSTUNサーバーをゼロから実装してもらい、シグナリングサーバーに同居させました。これでmDNSに隠されない「実IPアドレス」の接続候補も得られるようになり、Windows、Linux、Android間のP2P接続は無事に安定したのですが……。

Haiku OSだけは相変わらず「接続失敗」のままなんです。


犯人は、まさかの「そもそも存在しなかった」

網羅的に対策を打っても一向に直りません。ここで方針を変えて、Claude Codeに「ワンクリックでログ全文をテキスト表示できるボタン」をアプリ自体に追加してもらいました。Haiku OSは開発者ツールが使いづらいので、アプリの中にその場でコピペできる診断ログを用意したわけです。

そして表示されたHaiku側のログの2行目を見て、これまでの推理がすべて的外れだったことを悟りました……。

RTCPeerConnection: false

なんと、Haiku OS標準ブラウザ「WebPositive」には、そもそもRTCPeerConnectionというAPI自体が実装されていなかったんです!APアイソレーションでも、mDNSの解決失敗でも、JSONシリアライズのバグでもありませんでした。ブラウザにWebRTCという機能そのものが存在しないという、シンプルかつ身も蓋もない結論だったのです。ポリフィルでは絶対に解決できない、正真正銘のプラットフォーム制約でした。

ですが、「非対応でした」の一言で終わらせるのも寂しいので、Haiku OSに別のブラウザ(Firefox)を入れて試してみたところ――あっさり接続に成功!テキストもファイルも問題なく送受信できました。今回追加したSTUNサーバーやJSONの詰め替え対策も、Firefox on Haikuではちゃんと効いていたことになります。調査は無駄じゃありませんでした!

HaikuでもFirefoxなら接続成功
HaikuでもFirefoxなら接続成功!

2時間半後、たどり着いた場所

最終的に、WebSendは以下の環境で実際に動作するところまで完成しました!

  • Windows / Linux / Android
    • 標準ブラウザ同士でP2P接続・テキスト送信・ファイル送信すべて確認
  • Haiku OS
    • 標準ブラウザ「WebPositive」は非対応。Firefoxを入れればP2P接続・テキスト送信・ファイル送信すべて確認
  • Raspberry Pi 3B+
    • シグナリング兼STUNサーバーとして安定稼働
WebSendの画面
Windows 11 上の WebSend の画面

サーバーには最後まで1バイトのデータも残していません。ソースコードはMITライセンスでGitHubに公開しています。

リポジトリはこちら:taoman26/WebSend


今回の学び

  • デザイン先行は大正解でした。
    絵文字の豆腐文字問題のような小さなつまずきを、実装に入る前のコストが低い段階で潰せました。
  • 「小さく作って、その場で動かす」を徹底したからこそ大トラブルにも耐えられました。
    ①②③と段階を踏んで都度実機確認していたおかげで、最終盤の「接続できない」事件でも疑うべき範囲を素早く絞り込めました。
  • 「同じマシン上で動いた」は「別々の実機で動いた」の証明にはなりません。
    開発中の自動テストは同一マシン上の2つのブラウザで行っていたため、真のネットワーク越しのP2P疎通は実は検証できていませんでした。やはり実機を並べて初めて発覚するバグはありますね。
  • 原因不明のときほど、複雑な仮説より先に「そもそもAPIが存在するか」を疑うべきでした。
    APアイソレーション、mDNS、JSONシリアライズと、もっともらしい仮説を順番に潰していきましたが、答えは「機能が実装されていない」という一番シンプルな話でした。マイナーOSの検証では、まずここを疑うのが正解だなと痛感しました。
  • AIエージェントとの伴走は、原因追跡のスピードそのものを劇的に変えてくれます。
    STUNサーバーの実装、ログ機能の追加、Playwrightによる実機さながらの自動テストまで、次々と手を動かしてくれる相棒がいたからこそ、2時間という超短時間でここまでたどり着けました。

ハッカソンの最終成果物であるデモ発表のリハーサルとして、この記事を書きました。構想の30分に加えて開発・検証・ブログ執筆で3時間半、あわせてわずか 4時間でハッカソンを完走 です!当初想定していた8時間の半分で終わってしまい、我ながら驚いています。

AIで何をするか迷われている実務家の方は、まずAIを伴走者にしてハッカソンに参加してみてはいかがでしょうか?世界が変わってみえるはずですよ。


AI導入・プロダクト開発にお悩みの方へ

今回のようにAI開発エージェントを実際のプロジェクトでどう使いこなすかというテーマは、実際に体験してみないとなかなか実感として掴めないものです。そして実感が掴めると、何か作ってみたいと思うものです。

「自分も何か作ってみたい」と思われた方、そのアイデア、頭の中で寝かせておくのはもったいないかもしれません。

ビューローみかみでは、構想段階の壁打ちからPoC・実装・現場導入まで、現場で「使い続けられる」ものづくりを支援しています。

アイデアを短期間で「動くもの」にし、PoCで終わらせず、実運用まで伴走します。まずは「これ、作る価値ありますか?」という壁打ちからでも大歓迎です。

▶ PoC・MVP開発サービスの詳細はこちら

気になることがあればお気軽にご相談ください。

本日も最後までお読みいただき、ありがとうございました。

それでは、よいセルフハッカソンライフを!

カテゴリ: プロジェクト管理

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール