コンテンツにスキップ

MonoSpecs とは何か:なぜそれは OpenSpec のさらなるアップグレードと拡張であると言えるのか

ページを編集
HagiCode for Windows Microsoft Store artwork
HagiCode for Windows is now on Microsoft Store
HagiCode for Windows is officially live on Microsoft Store. Windows users can install it directly from the storefront and stay on the store-managed update path. Open the listing and take a look.
Open Microsoft Store

MonoSpecs とは何か:なぜそれは OpenSpec のさらなるアップグレードと拡張であると言えるのか

製品体系が 40 以上の独立した Git リポジトリに膨れ上がったとき、「規範」はどこに置くべきか?この記事では、HagiCode がマルチリポジトリガバナンスで行ってきた 2 つのステップについてお話しします:まず OpenSpec をメインリポジトリに引き上げ、その上で MonoSpecs というマルチリポジトリ管理ソリューションを発展させました。たいしたことではありません、ただいくつかの落とし穴を経験して、記録しておきたかっただけです。

背景

少し大きめの製品を作ったことがある人なら、こんな経験があるでしょう——最初はコードが 1 つのリポジトリだけで、規則正しく穏やかでした;その後、フロントエンド、バックエンド、デスクトップ、ドキュメントサイト、公式サイト、ビルドツールがそれぞれ独立したリポジトリになり、リポジトリの数は急増し、雑草のように手がつけられなくなりました。さらに後で、あるクロスリポジトリ機能のために「規範文書」を書こうとすると、どこに書けばよいか突然分からなくなりました。言ってみれば、子供の頃の小遣いが、なぜ突然なくなってしまったのかと感じるようなものです。

私たちの HagiCode はまさに、40 以上の独立した Git リポジトリで構成された製品体系です。初期段階では、OpenSpec の openspec/ ディレクトリをバックエンドサブリポジトリ hagicode-core に直接配置しました。結局バックエンドが核であり、ここに置くのが最も安定していると考えました。しかし、リポジトリがどんどん分割され、このソリューションは一連の頭痛の種となる問題を露呈しました。コードの世界は、あなたが「安定すると思った」からといって、実際に安定するわけではありません。

最初の痛点:specs が単一のサブリポジトリに閉じ込められている。ある機能がフロントエンド web とバックエンド hagicode-core の両方に影響する場合、hagicode-core で提案を書き、その後他のサブリポジトリでコード変更を実行する必要があります。提案がどのリポジトリに属すべきか、それ自体が論争になります。

2 番目の痛点:サブリポジトリが純粋でない。各サブリポジトリは自分の openspec/ を背負っており、規範文書と製品コードが混ざっています。誰かがあなたのフロントエンドリポジトリを clone すると、結果として大量のバックエンド提案文書を持って帰り、困惑します。

3 番目の痛点:AI Agent がリポジトリ間の関係を理解するのが難しい。各サブリポジトリは互いに独立しており、この製品がどのリポジトリで構成されているか、それぞれが何を担当しているか、どれが編集可能でどれが読み取り専用の参照であるかを AI に伝える機械可読の「リスト」がありません。

4 番目の痛点:クロスリポジトリ編集のコストが高い。spec を変更するには、対応するサブモジュールに cd する必要があり、パスがあちこちに飛び、コラボレーションの精神的負担が非常に大きい。

まさにこのような背景で、私たちはまず「OpenSpec Monorepo Migration」を行い、specs をサブリポジトリから monorepo のルートディレクトリに引き上げました。そしてその上で、MonoSpecs というマルチリポジトリ管理ソリューションを発展させました。この 2 つのステップの進化関係を理解することが、「なぜ monospec は openspec のさらなるアップグレードと拡張であると言えるのか」を理解する鍵です。

HagiCode について

この記事で共有するソリューションは、私たちが HagiCode プロジェクトで得た実践的な経験から来ています。HagiCode は AI コードアシスタントプロジェクトであり、リポジトリ数が多く、クロスランゲージコラボレーションが頻繁で、このような構造の複雑さは、「規範」と「リポジトリガバナンス」の両方を確実に実行することを私たちに強いています。MonoSpecs このソリューションは、このようなマルチリポジトリの実践の中で少しずつ磨き上げられたものです。何か特別な魔法があるわけではなく、ただいくつかのステップを踏んだだけです。

OpenSpec が解決するのは「規範をどう書くか、どう進化させるか」

両者の関係を明確に説明するには、それぞれが何を担当しているかを分解して見る必要があります。

OpenSpec は本質的に spec-driven の変更管理ワークフローです。その核心となる成果物は次のようになります:

openspec/
├── specs/ # 現在有効な能力規範(各能力ごとに 1 つの spec.md)
├── changes/ # 進行中の提案
│ └── archive/ # アーカイブされた履歴提案
└── project.md

それが答える質問は:ある変更は提案(proposal)、設計(design)、タスク(tasks)、アーカイブ(archive)のようなライフサイクルを経て、アーカイブ時に deltas を specs にマージする必要があります。このメカニズム自体は「リポジトリがいくつあるか、どこにあるか、誰が管理しているか」とは無関係であり、spec ファイルをどう組織するかだけを気にします。

私たちは移行提案を通じて、元々 hagicode-core/openspec/ に分散していた 82 以上の spec ファイルを monorepo ルートディレクトリの openspec/ に引き上げ、すべての spec を 1 か所で統一的に見えるようにし、統一的なバージョン管理を行いました。

しかし、この移行は正直に言うと「spec ファイルの移転」だけであり、より根本的な質問には答えていませんでした:この monorepo は具体的にどのサブリポジトリで構成されているのか?これらのサブリポジトリ間の関係は何か?これが MonoSpecs が埋めるべき部分です。

MonoSpecs が解決するのは「マルチリポジトリ自体をどう管理するか」

MonoSpecs の核心は、機械可読のリストファイル:.hagicode/monospecs.yaml です。それは OpenSpec がまったく関与しない 4 つのことを行います。

1 つ目:サブリポジトリリストの宣言。各リポジトリの path、url、displayName、icon、tags、“More” に折りたたむかどうかをすべて 1 つの YAML に書き、一目瞭然にします。

2 つ目:clone スクリプトの駆動scripts/clone-repos.mjs は直接この YAML を読み取り、一括で git clone を行い、リポジトリリストをハードコードしません。リポジトリを追加するには YAML に 1 行追加するだけで、スクリプトはゼロ変更です。

3 つ目:AI/IDE にプロジェクト構造コンテキストを提供AGENTS.md と連携して、AI Agent はどのリポジトリが編集可能で、どれが reference-only で、技術スタックが何であるかを一目で判断できます。

4 つ目:OpenSpec の成果物をメインリポジトリにアンカー。specs は各サブリポジトリに散らばらず、メインリポジトリのルートディレクトリの openspec/ に統一的に収集され、サブリポジトリは純粋を保ちます。

2 つの意味、混同しないでください

MonoSpecs の公式ガイドでは、非常に混同しやすい場所が明確に指摘されています:MonoSpecs には実際に2 つの意味があります。

1 つは設定システム層で、.hagicode/monospecs.yaml という設定ファイル自体、およびそれに付随するロード、検証、キャッシュメカニズムを指します。

もう 1 つはリポジトリタイプ層で、「メインリポジトリ + 複数のサブリポジトリ + 集中 specs」というリポジトリ組織モードを指します。プロジェクトが「MonoSpecs プロジェクトである」と言うときは、この構造を採用していることを意味します。

この 2 つの層が重なってこそ、完全な MonoSpecs です。多くの人が初めて接触するとき、YAML ファイルの層しか見えず、MonoSpecs は設定リストだと思いがちですが、実際の価値は 2 番目の層にあります——明確なマルチリポジトリコラボレーションパラダイムです。実は、美しいものは往々にして最初の目にはなく、数回見る必要があります。

なぜ「アップグレードと拡張」と言えるのか

両者を一緒に比較すると、関係が明確になります:

次元OpenSpecMonoSpecs
関心点spec ファイルの内容とライフサイクルリポジトリの組織構造とリスト
核心成果物openspec/specs/*/spec.md.hagicode/monospecs.yaml
相手に依存するかMonoSpecs に依存しないOpenSpec に依存し、その openspec/ を再利用して変更管理を行う
解決する痛点規範をどう書くか、どう進化させるかマルチリポジトリをどう宣言するか、どう clone するか、AI がどう理解するか
作用範囲どのリポジトリでも使用可能「一主多子」のマルチリポジトリ構造専用に設計

正直に言うと、MonoSpecs は OpenSpec を置き換えたのではなく、その上に「リポジトリガバナンス」の層を追加しました。monospecs.yaml でリポジトリトポロジーを記述し、集中式 openspec/ で spec とサブリポジトリを分離し、commit_when_archive でアーカイブを自動的にメインリポジトリに保存させます。

もし比喩を使うなら:OpenSpec は「変更構文」を提供し、MonoSpecs は「マルチリポジトリセマンティクス」を提供します。前者は後者の前提であり、後者は前者の拡張です。すべての道はローマに通じますが、今回は、道が想像より少し長いだけです。

どう実装するか:4 ステップ

ステップ 1:メインリポジトリと設定ファイルを確立する

monorepo ルートディレクトリに設定ファイルを配置し、すべてのサブリポジトリを宣言します。私たち自身のプロジェクトを例にすると、構造はだいたい次のようになります:

.hagicode/monospecs.yaml
version: "1.0"
commit_when_archive: true
repositories:
- path: "repos/web"
url: "https://github.com/HagiCode-org/web.git"
displayName: "フロントエンド"
tags: [frontend, react, pcode-client]
- path: "repos/hagicode-core"
url: "https://github.com/newbe36524/pcode"
displayName: "バックエンド"
tags: [backend, dotnet, orleans]
- path: "repos/docs"
url: "https://github.com/HagiCode-org/docs.git"
displayName: "ドキュメント"
tags: [docs, astro, starlight]
ui:
collapseToMore: true # UI で "More" の後に折りたたむ

いくつかのフィールドに特に注意する必要があります:

  • path はメインリポジトリルートに対する相対パスであり、各レコードのユニークキーでもあります。
  • url は Git リモートアドレスであり、clone スクリプトはそれに依存してコードをプルします。
  • displayName / icon / tags は UI 表示と AI コンテキストにのみ影響し、clone 動作には影響しません。
  • commit_when_archive: true は、OpenSpec 提案のアーカイブ時に自動的にメインリポジトリに commit させます。

ステップ 2:OpenSpec をメインリポジトリルートディレクトリに引き上げる

移動前後の比較は次のとおりです:

移動前(specs がサブリポジトリに閉じ込められている) 移動後(specs がメインリポジトリに集中)
hagicode-core/ . (メインリポジトリルート)
└── openspec/ ├── .hagicode/monospecs.yaml
└── specs/ (82+ specs) ├── openspec/
│ ├── specs/ (集中管理)
│ └── changes/
└── repos/
├── hagicode-core/ (純粋、openspec なし)
├── web/
└── docs/

サブリポジトリは今後 openspec/ を背負わず、メインリポジトリが唯一の spec トラースソースになります。このステップは単純に見えますが、もたらされる利益は非常に実在します——どのエンジニアでもメインリポジトリのルートディレクトリに立つだけで、製品体系全体のすべての規範を見ることができます。

ステップ 3:clone スクリプトに設定を読ませてハードコードをやめる

scripts/clone-repos.mjs の核心ロジックは YAML を読み、1 つずつ clone することです:

const CONFIG_PATH = path.join(__dirname, '..', '.hagicode', 'monospecs.yaml');
// repositories 配列を解析
// 各条に対して git clone <url> <path> を実行
// 目標ディレクトリが存在する場合はスキップまたは git pull

リポジトリを追加するときは、YAML に 1 行追加するだけで、スクリプトを変更する必要がありません。この小さな変更は、無数の「リポジトリリストを同期するのを忘れた」という揉め事を節約します。誰も繰り返し労働したいのでしょうか?

ステップ 4:バックエンドが統一された MonoSpecs サービス層を提供する

抽象化レイヤーを抽出しないと、設定解析ロジックは簡単に GitAppServiceProjectAppService の各所に散らばってしまいます。HagiCode は ClaudeHelper モジュールで IMonoSpecsService を抽出し、一連の明確な能力を外部に公開しました:

public interface IMonoSpecsService
{
Task<MonoSpecsConfigDto> GetConfigAsync(string projectPath);
Task<List<RepositoryInfoDto>> GetSubRepositoriesAsync(string projectPath);
Task<MonoSpecsDataDto> GetMonoSpecsDataAsync(string projectPath);
Task<MonoSpecsManagementDto> GetManagementDocumentAsync(string projectPath);
Task<MonoSpecsManagementDto> InitializeManagementDocumentAsync(string projectPath);
Task ValidateManagementDocumentAsync(string projectPath, UpdateMonoSpecsManagementRequestDto request);
Task SaveManagementDocumentAsync(string projectPath, UpdateMonoSpecsManagementRequestDto request);
}

このサービスは設定のロード、検証、キャッシュを担当し、「最小テンプレートの初期化」能力を提供します——空のプロジェクトにワンクリックで monospecs.yamlrepos/openspec/changes/archive/openspec/specs/ スケルトンを生成し、自動的に .gitignore を補完します。キャッシュは記憶のようなもので、一度覚えれば、次は苦労して考えなくて済みます。

実践でのいくつかの落とし穴

全く新しい MonoSpecs プロジェクトを初期化する

InitializeManagementDocumentAsync を呼び出した後、ディスク上に次のような構造が現れます:

my-project/
├── .gitignore # repos/ 無視ルールを追加(べき等、重複して追加しない)
├── .hagicode/
│ └── monospecs.yaml # 最小テンプレート:version / commit_when_archive / repositories: []
├── openspec/
│ ├── changes/archive/
│ └── specs/
└── repos/ # 空ディレクトリ、clone を待つ

ここで注意すべき境界がいくつかあり、すべて spec から抽出したものです:

  • べき等:既存の repos/openspec/ ディレクトリは保持され、エラーになりません。
  • 上書きしないmonospecs.yaml が既に存在し、正常に解析できる場合、初期化はそれを変更せず、欠落している .gitignore ルールと openspec ディレクトリのみを補完します。
  • 汚れた設定を拒否:既に存在しているが解析できない monospecs.yaml は直接拒否され、診断可能なエラー情報を返し、絶対に上書きしません。
  • 自動スキャンしない:初期化は独断でディスクディレクトリをスキャンしてリポジトリエントリにせず、repositories はデフォルトで空で、手動または UI で記入する必要があります。

設定ファイル位置の移行トラップ

歴史的に monospecs.yaml はプロジェクトルートディレクトリに置かれていましたが、後に強制的に .hagicode/monospecs.yaml に移行されました。この点は spec で非常に明確に書かれています:

ルートディレクトリの monospecs.yaml は検出されず、互換性フォールバックともなりません。clone スクリプトは .hagicode/monospecs.yaml のみを認識します。

したがって、古いプロジェクトをアップグレードするときは、手動で mv monospecs.yaml .hagicode/monospecs.yaml を実行する必要があり、いかなるサイレント互換性のパスもありません。一見不人情に見えますが、よく考えてみると、これは「2 つの場所が有効になる可能性がある」というあいまいさを完全に排除するためです——このあいまいさが一度存在すると、問題をトラブルシューティングするときに人を狂わせることができます。誰も 2 つのファイルの間で答えを行ったり来たりしたいのでしょうか。

保存検証:無効な設定を書かない

SaveManagementDocumentAsync で書き戻す前に、サービスはフィールドレベルの検証を行います。いくつかの典型的な拒否シナリオ:

  • 2 つのリポジトリエントリの path が重複 → 拒否、競合フィールドを返す。
  • いずれかのエントリに path がない → 拒否、必須エラーを返す。
  • url が空でないが合法的な絶対 URL ではない → 拒否。

検証に合格した後にのみ YAML にシリアル化してディスクに書き込み、同時にそのプロジェクトパスの設定キャッシュを無効にし、次回の読み取りで最新の内容を取得できるようにします。このステップは些細に見えますが、無数の「設定を変更したのに有効にならない」というチケットを回避できます。これらのチケットが増えると、誰も耐えられません。

workspace モード vs 手動 repositories モード

設定ファイルは 2 つの派生リポジトリリスト方式をサポートしています。

1 つは手動 repositories モードで、YAML に各リポジトリを直接リストし、管理ドキュメントは編集可能としてマークされます。

もう 1 つはworkspace モードで、.code-workspace ファイルを宣言し、それからリポジトリリストを派生させます。このモードでは管理ドキュメントは読み取り専用としてマークされ、リポジトリ配列を直接書き換えることは禁止され、サポートされるトップレベルフィールドのみ変更できます。

私たち自身の HagiCode Mono は現在 workspace モードをコメントアウトし、手動モードを採用しています。理由は簡単です:手動モードでは各リポジトリの icon と tags を細かく制御でき、UI 表示効果をより制御しやすいからです。言ってみれば、制御できるものは、やはり心が安心です。

AI Agent への実践的提案

現在 AI プログラミングがますます普及しており、MonoSpecs このソリューションには実は 1 つの隠された価値があります:それは AI に構造化されたプロジェクトマップを提供することです。

マルチリポジトリコラボレーションでは、AGENTS.mdmonospecs.yaml は AI への 2 つの重要なコンテキストです。推奨されるワークフローは次のとおりです:

  1. まず monospecs.yaml を読んでリポジトリトポロジーを取得し、誰が編集可能で、誰が reference-only かを明確にします。
  2. 次にルート AGENTS.md の “Active Edit Scope” を読み、現在許可されている変更範囲を確認します。
  3. クロスリポジトリ変更はメインリポジトリルートの openspec/changes/ で提案を統一し、各サブリポジトリで別途 openspec を開始しないでください。

この規約により、AI は「メインリポジトリが specs を管理し、サブリポジトリがコードを管理する」という分業を安定して理解でき、spec を誤ってサブリポジトリに書き込むことはありません——この誤操作は私たちが前に何度も踏んだ落とし穴です。実は AI のせいでもありません、毕竟サブリポジトリとメインリポジトリはとても似ていて、誰でも一目で区別できるでしょうか?

まとめ

一言でまとめると:OpenSpec は「変更をどう書くか」を定義し、MonoSpecs は「リポジトリをどう配置するか」を定義します

前者は後者の構文基礎であり、後者は前者を単一リポジトリコンテキストからマルチリポジトリコンテキストに拡張し、YAML リストでリポジトリトポロジー、clone プロセス、AI コンテキスト、specs の帰属を一度に収束させます。これが「monospec は openspec のさらなるアップグレードと拡張である」の真の意味です——置き換えではなく、その上にマルチリポジトリセマンティクスの層を追加しました。

あなたも同様の規模のマルチリポジトリ製品を作っているなら、この 2 つの層が整備されているか考えてみてください。規範がどんなに美しく書かれていても、明確なリポジトリガバナンスが支えていなければ、最終的には混乱してしまいます…

参考資料

まとめ

「MonoSpecs とは何か:なぜそれは OpenSpec のさらなるアップグレードと拡張であると言えるのか」をめぐって、より確実な推進方法は、まず重要な設定、依存境界、実装パスを徐々に実行し、その後最適化の詳細を補完することです。

目標、ステップ、検収ポイントが明確になった後、この種のソリューションは通常よりスムーズに実際のデリバリーに入ることができます。

开始使用 HagiCode

一次安装,几分钟上手

HagiCode for Windows 在 Microsoft Store 免费提供。打开商店即可安装并保持更新;也可以先对比各版本与定价,再决定从哪个渠道开始。