ローカルファーストである理由
skillshare はランタイム依存のない単一バイナリです。その理由を説明します。
その決断
skillshare は単一の Go バイナリとして配布されます。Node.js も、Python も、パッケージマネージャーも、デーモンも不要です。インストールして実行するだけで完了です。
これは単に楽な道を選んだのではなく、3 つの原則に基づく意図的な選択です。
原則 1: 依存関係チェーンをゼロにする
すべての依存関係は攻撃対象領域であり、保守の負担でもあります。
もし skillshare が Node.js を必要としていたら、Node のバージョン管理、node_modules の扱い、プラットフォーム固有のネイティブモジュールへの対応、そして npm のサプライチェーン全体への信頼が必要になります。AI の Skill——それ自体が信頼できないコンテンツ——を管理するツールにとって、信頼できない依存関係チェーンを追加することは受け入れられません。
Go は静的バイナリにコンパイルされます。依存関係チェーンはコンパイル時点で終わります。ダウンロードしたものがそのまま実行されるものです。
原則 2: どこでも同じように動く
skillshare は次の環境で動作します。
- macOS(Intel および Apple Silicon)
- Linux(amd64 および arm64)
- Windows(amd64)
- Docker コンテナ(特別なセットアップ不要)
- CI/CD パイプライン(言語ランタイム不要)
- Dev Container と Codespaces
単一バイナリであることは、すべてのプラットフォームで同一の挙動を意味します。「自分のマシンでは動く」というデバッグも、CI 環境のずれもありません。
原則 3: デフォルトでオフライン動作する
skillshare のコア操作——sync、list、status、backup、restore——はネットワークアクセスなしで動作します。明示的に remote を必要とする操作(install、search、check、update、push、pull)だけが接続を必要とします。
これは次のような場面で重要になります。
- エアギャップ環境: 防衛、医療、金融機関ではネットワークアクセスが制限されることが多い
- 不安定な接続: 電車、飛行機、カンファレンスの Wi-Fi
- 速度: ローカル操作は秒単位ではなくミリ秒単位で完了する
なぜパッケージマネージャーのプラグインにしなかったのか
npm パッケージ、Homebrew formula(現在は追加のチャネルとしてサポート)、pip パッケージとして配布することも検討しました。しかしどれも同じ問題を抱えていました。skillshare のユーザーが持っていない、あるいは望まないランタイム依存を追加してしまうのです。
Windows で Cursor を使っている開発者が Homebrew をインストールする必要はないはずです。Alpine Linux 上で動く CI パイプラインが Node.js を必要とするべきではありません。ツールはユーザーの環境に合わせるべきであり、その逆であってはなりません。
トレードオフ
単一バイナリのアプローチには代償があります。
- ビルドの複雑さ: 6 以上のターゲットへのクロスコンパイル、CGO は無効化
- 更新の仕組み:
npm updateは使えないため、skillshare 独自のupgradeコマンドを用意している - UI の配布: Web ダッシュボードはバイナリに同梱できないほど大きいため、実行時にダウンロードしてキャッシュする
これらのトレードオフを受け入れているのは、それによってユーザー体験をシンプルに保てるからです。ダウンロードして、実行して、それで完了です。