これはフェンリル デザインとテクノロジー Advent Calendar2025 20日目の記事です。
こんにちは!
NILTOチームでインフラエンジニアをしている太田です。
みなさんは、Gitのリポジトリ管理方法で「Monorepo」や「Polyrepo」という言葉を聞いたことはありますか?
Monorepo(モノレポ)は、単一のリポジトリで複数のプロジェクトを管理する手法です。一方、Polyrepo(ポリレポ)1は、プロジェクトごとにリポジトリを分割して管理する手法です。
私はMonorepoを使うのが好きで、プライベートでは1つのリポジトリにすべてのコードやドキュメント、画像などのバイナリファイル2を保存して管理しています。また、個人的にWindowsとmacOS(たまにLinux)を切り替えて使うことも多く、どちらでも同じリポジトリで作業したくなることがあります。そんな時、両方の環境で使えるモノレポがあると便利です。
今回は、そんな私の「秘密基地」であるマルチプラットフォーム対応3のモノレポを、どうやって構成しているか紹介します。
※本記事で紹介するリポジトリは、外部に公開しないプライベートなリポジトリを想定しています。
※下記でリンクを載せているリポジトリは公開用サンプルです。実際は現在も裏で改修や増築を続けています。
リポジトリ構成
GitHubでサンプルのリポジトリを公開しています。見ながら読むと分かりやすいかと思います。
https://github.com/sakai-nako/monorepo-secret-base
フォルダー構成は以下のようにしています。
monorepo-secret-base/ ├── .agent/ # AIエージェント向けの手順書(about-this-repository.mdなど) ├── .moon/ # moonrepoの全体設定(workspace.ymlなど) ├── artifact/ # ビルド成果物(git管理外) │ └── apps/ # 生成されたアプリの実行ファイルがここに集まる ├── source/ # 各言語のソースコード │ ├── js-ts/ # Node.js (pnpm workspace) │ │ ├── packages/ # - sample-app-node など │ │ └── pnpm-workspace.yaml │ ├── python/ # Python (uv workspace) │ │ └── sample-app-python/ │ └── rust/ # Rust (cargo workspace) │ │ ├── crates/ # - sample-app-rust など │ │ └── Cargo.toml ├── submodule/ # 外部リポジトリ(Git Submodule) ├── task-script/ # マルチプラットフォーム対応用スクリプト。Justfileだと長くなる複雑な処理は、Pythonで書いてここに配置 │ └── rust_install_bin.py ├── .gitignore ├── .python-version # Pythonバージョンの固定 (3.13) ├── Justfile # タスクランナー定義(全体の司令塔) ├── pyproject.toml # Python依存管理 & uv workspace設定 └── uv.lock
こだわりポイント
Justによるタスクランナーの統合
このリポジトリでは、タスクランナーとしてJustを採用していて、ルートディレクトリにあるJustfileに、プロジェクト全体でよく使うコマンドを定義しています。
例えば、言語ごとの初期セットアップを行うjust initや、ビルドシステムのmoonを呼び出すjust mtなどのエイリアス4を用意しています。こうすることで「Pythonプロジェクトだからuvを使って……」「Rustだからcargoを使って……」といったコマンドの違いを意識せず、統一されたインターフェースで操作できるようになります。5
特に、WindowsとmacOSを行き来する場合、コマンドの違い(cpとcopyなど)をJustやPythonスクリプトで吸収できるのが大きなメリットです。6
moonによるビルドシステムの統合
モノレポのビルド管理にはmoon7を使用することにしました。.moon/workspace.ymlでsource/python/*、source/rust/*、source/js-ts/*といったディレクトリを指定することで、異なる言語のプロジェクトをまとめて管理しています。
moonでも、Justと同じようにタスク(コマンド)が定義できます。また、プロジェクトの依存関係を解析して変更があった部分だけをビルドしたり、タスクの実行結果をキャッシュして高速に動作させたりしてくれます。
moonのタスクも簡単に実行できるように、Justからmoon run <project>:<task>を呼び出す形で連携させています。
分けておきたいリポジトリはGit Submoduleで管理
プライベートリポジトリの中で「このツールだけは公開したい!」といった場合や、Zennのような「リポジトリのルートが連携対象となる(サブディレクトリを指定できない)」サービス用のリポジトリを管理したい場合もあります。また、オープンソースのGitHubリポジトリを、秘密基地の中で編集したくなることもあります。
そこで、外部のオープンソースリポジトリや、公開用・サービス連携用のリポジトリは、submodule/ディレクトリ配下にGit Submoduleとして配置しました。これで、メインの「秘密基地」はプライベートなままシンプルに保ちつつ、必要な外部リソースや公開プロジェクトも一緒に管理できる状態になりました。
AIエージェントとも仲良く
最近はClaude CodeやGemini CLIを使ってAIエージェントと一緒にコーディングすることが当たり前になってきました。そこで、このリポジトリには.agentディレクトリ8を用意し、AIエージェント向けの手順書やルール(about-this-repository.mdなど)を配置しています。
例えば「コマンド実行はなるべくJustを経由すること」や「ファイル操作はプラットフォーム依存を避けるためPythonスクリプトを使うこと」といったルールを明記することで、AIが迷わずに適切な操作を行えるように促しています。これによって、AIにお願いした時に「Windowsだから動かないコマンドを提案された……」といったトラブルが減り、快適なペアプログラミングの世界に一歩近づきます。
おわりに
今回は、私のプライベートな「モノレポ秘密基地」の構成を紹介しました。いろいろな道具(Just、moon、AIなど)を組み合わせることで、自分にとって居心地の良い開発環境を作っていくのはとても楽しいです。
今年の年末年始は、みなさんもぜひ「ぼくの考えた最強のモノレポ秘密基地」作りにチャレンジしてみてください!
それでは、少し早いですが……ハッピーホリデー!
- Multi-repoとも呼ばれます↩
- テキスト形式ではないファイル(画像・音声・動画など)のことです↩
- WindowsでもmacOSでもLinuxでも、同じリポジトリでストレスなく作業できる状態、の意図です↩
- コマンドの別名です。長い名前のコマンドが多くなるので、短い名前でサッと呼び出せるようにしています↩
-
他のリポジトリでもJustを使うことが多いので、ターミナル(黒い画面)でまずは
justを打つのが習慣になってきてます↩ - OSによるコマンドの違いには、ハマることが多いですよね……↩
- moonはちょっと前に使っていた時期があるのですが、Justを使うようになってから疎遠になってました↩
-
.agentディレクトリは、Googleが開発しているAntigravityというエディタで利用されています↩