個人ツール

PWAをやめて、Mac上のHermesをiPhoneから使う専用アプリを作った

Mac上のHermesセッションを外出先から続けるため、PWAを廃止してSwiftUIアプリへ。VPS・mTLS・SSHトンネルを使った個人用Remoteの構成と判断をまとめます。

Hermes Desktop を使っていると、作業場所を移したあとも Mac 上のセッションを続けたくなります。そこで、外出先の iPhone から Mac 上の Hermes を操作する個人用クライアント「Hermes Remote」を作りました。

最初は PWA を用意しましたが、最終的にはそれを廃止し、SwiftUI の iOS アプリだけを残しました。この記事では、画面をスマホへ移すときにどこまでを Mac に残したか、接続をどう守ったか、PWA からネイティブへ切り替えた判断を記録します。

iPhoneからMac上のHermesへつながるHermes Remoteの構成

iPhone は操作画面を担当し、Hermes と開発環境は Mac 上で動き続ける。

操作画面を移しても、実行環境は Mac に置く

Hermes Remote は、Mac の画面をそのまま配信するリモートデスクトップではありません。iPhone からセッション一覧を開き、会話の続きを送り、ツールの動作や承認待ちを確認するクライアントです。会話履歴は Hermes のセッションと共有し、Mac 側の実行環境を使います。

モデル呼び出し、ツール実行、ローカルの認証情報は Mac に残します。iPhone にターミナルやモデル API キーを持たせず、スマホ側には会話操作と必要な確認画面を置く方針です。実装したのは、一覧とチャット、Markdown 表示、ツール活動、停止や指示の追加、承認・質問への応答、添付、音声入力などです。

音声入力も同じ分担です。iPhone は録音し、音声を Mac 側へ送り、Mac の音声認識で文字にします。音声認識の設定やプロバイダの認証情報をスマホに複製せずに済みます。

公開 URL の先に Mac を直接さらさない

外からつなぐには入口が必要ですが、Mac の開発用サーバーをそのままインターネットへ公開する構成にはしませんでした。通信は、iPhone からの HTTPS を VPS のリバースプロキシで受け、相互 TLS と SSH のリバーストンネルを通して Mac 側の ingress、bridge、Hermes の順に届けます。

Mac の bridge は API と WebSocket を中継します。HTTP のリクエストだけでなく、会話のストリーミングや進行中の活動も WebSocket で扱います。公開側の入口、Mac へ戻るトンネル、アプリ本体の役割を分けることで、Hermes の実行プロセスを直接公開しない形にしました。

初回接続は短時間だけ有効なペアリングコードで行い、その後は端末ごとのトークンで認証します。iOS アプリではトークンを Keychain に保存します。未ペアリング端末からの操作は拒否し、スマホにフルシェルや Git の書き込み機能を足さない方針も保っています。差分レビューは読み取り専用にし、Remote FS の対象も開発ディレクトリの内側に制限しました。

PWAを残さずSwiftUIで作り直した

最初のクライアントは Web 技術で作った PWA でした。その後、自分が使うクライアントを開発用 iOS アプリに一本化すると決め、PWA を WKWebView に包む方法ではなく、SwiftUI で同じ Remote の体験を作り直しました。PWA とネイティブ版を並行して保守しない、という運用上の選択です。

ネイティブ版では通知に APNs を使い、ペアリング後のトークンを Keychain に保存します。アプリが前面に戻ったときは WebSocket を張り直します。こうして自分が使う iPhone アプリへ実装を集め、PWA は 2026年9月に廃止しました。

これは一般公開するアプリではなく、自分の端末で使う開発用アプリです。App Store へ出さず、Ad Hoc 署名で実機に入れています。そのため配布や更新はストアアプリのようにはいかず、署名や端末登録を含めて自分で管理します。対象端末を限定できる一方、端末を替えるときはビルドとインストールの手順も必要になります。

リモートに増やす機能を絞る

スマホへ Mac と同じ操作を全部持ち込むと、画面が複雑になり、誤操作時の影響も大きくなります。そこで、外出先で必要な操作を先に選びました。会話の確認・送信、進行中のツールの確認、承認・質問への応答、停止、指示の追加が中心です。

差分レビューや Remote FS も追加しましたが、役割を確認や限定的な編集に留めています。任意のシェルを実行したり、Git の変更をコミット・破棄したりする操作は移植していません。便利そうな機能を並べるより、スマホに持たせた権限と操作を説明できるようにすることを優先しました。

この境界を維持するには、見た目だけでなく Mac 側の API でも端末トークンを検証し、対象パスや操作の範囲を制限する必要があります。クライアントのボタンを隠すだけでは、リモート操作の制御にはなりません。

個人用Remoteを作って分かったこと

このプロジェクトで一番大きかったのは、スマホ用の画面を作ることより、どの機能をスマホに許し、どの処理を Mac に残すかを決めることでした。セッション状態を共有しながら、認証情報やツール実行を Mac に置く。接続は VPS とトンネルで中継し、ペアリング済み端末だけを通す。これらを先に分けたことで、機能を増やしても境界を見直しやすくなりました。

また、PWA とネイティブアプリを両方保守するのではなく、毎日使う端末と用途に合わせて一方へ絞る判断もしました。自分用の道具なら、公開範囲や配布先を小さく保ったまま、必要な操作に時間を使えます。

個人開発で自前のリモート操作面を作る場合、まず「スマホで何でもできること」ではなく、「Mac に残すべき実行環境は何か」「端末側に渡す権限はどこまでか」を決めると、接続方式や画面の範囲も選びやすくなります。

← 記事一覧