Go back

Grok の並列マルチタスクで MT プラグインを一気に進めた記録

Posted on:

Movable Type の MCP プラグイン(mt-plugin-mcp)を、Cursor の Grok(Grok 4.6)とマルチタスク・サブエージェントで一気に進めました。そのときの学びを、いったん全部書き出します。きれいに整える前の素材置き場です。

触った親 issue は 実装ロードマップ #26。P1/P2 を実装して閉じ、積む分は 検討中 #44 に移しました。

やったことのざっくり時系列

  1. Issue #26 の P1(Folder / Page / TemplateMap / Widgetset)をサブエージェントで実装
  2. 機能ごとに 別コミット・別 PR(#27〜#30)。Protocol.pm などが共有なので スタック
  3. P2 を issue ごと別 worktree・別 PR(#31〜#37)。独立なものは同じ base から並列、依存は直列
  4. GitGuardian がテスト用パスワードを拾った → HEAD 修正だけでは足りず、履歴から消して force-push
  5. 並列 PR が main に入るたびに コンフリクト。base をマージして通常 push
  6. CodeRabbit コメント対応
  7. 意図的に外したギャップを整理。全部スキップしてよいわけではなかった
  8. 後続 issue を起票(#38〜#40)。親のサブ issue 化を忘れ、あとから API で付けた
  9. README を導入中心に、ツール一覧は docs/ へ(#41 / PR #43)。AGENTS.md は別 issue(#42 / PR #45)
  10. P3 と後続を 検討中の親 #44 へ移動して #26 をクローズ
  11. 後続は #38 → #39 → #40 export → #40 import の順で別 worktree(PR #46/#48/#49/#50)
  12. 人間向けオンボーディングは別エージェント・別 worktree(PR #47)
  13. リモートタグの v 漏れを直し、main HEAD に v0.7.0

Grok を使った並列開発(マルチタスクエージェント)

Cursor 側の動き

親エージェントはコーディネータに寄せました。調査・実装・テスト・PR 作成はバックグラウンドのサブエージェントに渡します。親は「何を・どの順で・どこまでやってよいか」をプロンプトに書きます。

うまくいった渡し方は次のとおりです。

  • 1 リクエスト = 1 つの一貫した仕事(P1 実装、コンフリクト解消、issue クローズ、など)
  • 独立している仕事だけ 親から複数エージェントを同時起動(後続ツール列とオンボーディング docs は別ストリーム)
  • 依存がある仕事は 1 エージェントが内部で直列(#38 が push されてから #39 の worktree、のように)
  • 作業場所は dirty な元 worktree を使わず git worktree add で隔離
  • コミットは git add . 禁止、名前付きファイルだけ。force-push は明示承認があるときだけ

親から見た並列の形はこうなります。独立ストリームだけ同時に切り、依存は子の中で直列にします。

失敗しやすい渡し方も挙げておきます。

  • 同じ worktree に複数エージェントを同時に入れる(ファイルがぶつかる)
  • 「P2 全部並列」とだけ言って Protocol.pm の共有を無視する
  • サブエージェントが終わったあとに親が同じ調査をやり直す(無駄)

並列化してよいものと、してはいけないもの

コードが独立でも、登録簿は共有でした。このリポジトリではだいたい次がぶつかります。

  • plugins/MTMCP/lib/MTMCP/Protocol.pm(ツール登録)
  • README.md / のちの docs/tools.md
  • config.yaml のバージョン
  • t/lib/ のスタブ

なので:

  • 並列してよい: Folder.pm と Page.pm のようにモジュールとテストが分かれている実装
  • 直列にする: Protocol への配線、README、バージョン bump、同じ Template.pm を触る変更
  • スタックする: 実装は並列に進めても、PR の base は「先に入る枝」にする

P2 では keyword / tag / log を同じ add/widgetset から同時に切りました。それぞれ独立に見えますが、先頭 PR 同士が Protocol と README で衝突します。マージはスタックを直列にしないと毎回コンフリクトします。

実装はモジュールを横に並べ、配線とマージだけ縦にします。P2 の 3 スタックは先頭同士がぶつかるので、スタックの中だけでなくスタック同士も直列にします。

サブエージェントに必ず書かせた制約

  • P3 を勝手に実装しない
  • main へ force-push しない
  • フックを飛ばさない
  • 秘密情報をログに出さない
  • 元 worktree の未コミット P1 を巻き込まない

「やらないこと」を先に書くと、エージェントがロードマップを先読みして P3 まで作ることが減りました。

Grok と Claude の体感(リミットと余裕)

同じような「issue を分解してエージェントに実装させる」を Claude 側でもやると、すぐリミットに当たりました。長いコンテキスト、サブエージェントの往復、PR コメント対応、コンフリクト解消のログが重いからだと思います。

Grok は、このセッションでは リミットを気にせず P1 → P2 → ラップアップ → 後続 → docs まで続けられました。体感の差は「1 本の賢い会話」より 何本も同時に回せるか に出ています。ストリームごとの時刻と件数は、下の「並列セッションの数字」に置きました。

ドル金額は出しません。Cursor の Usage ダッシュボード(2026-08-15 分)では Included が 7.3M、On-demand は 0 でした。New Relic ではこのセッションの費用は取れませんでした。

「速い」の中身は、モデルが Perl を速く書くことより、待ち時間を別ストリームで埋められることでした。オンボーディング docs を書いているあいだに #38〜#40 のスタックが進む、という使い方です。

タスクを回すときの issue の作業順と整理

親 issue はロードマップ、子は実装単位

#26 は「Data API 由来のツールをどの順で足すか」の親です。P0/P1/P2/P3 と対象外(NOT_PLANNED)が書いてありました。

実装 PR は 子 issue 1 つ(または明確なスライス)につき 1 PR にしました。

  • P1: #8 Folder、#5 Page、#12 TemplateMap、#13 Widgetset
  • P2: #19 keyword、#6 preview、#14 tag、#7 category / category set、#15 log、#10 user

「全部 #26 に突っ込む巨大 PR」はレビュー不能です。逆に「ファイル単位のミクロ PR」は Protocol の配線が毎回コンフリクトします。機能境界 × 依存のスタックがちょうどよかったです。

作業順の決め方

  1. Issue 本文から P1/P2 と依存グラフを書く
  2. 独立モジュールから並列実装
  3. 共有スタブ → 各ツール → Protocol / README は直列
  4. マージは 下の層から(フォルダの次にページ、のようにプロダクト依存があるならその順)
  5. コンフリクトしたら「最新 main を feature にマージして通常 push」。履歴を勝手に rebase しない(承認がない限り)

P2 の実マージはおおよそ次のとおりです。

  • 先に P1 スタック #27 → #28 → #29 → #30
  • そのあと P2 は 3 本のスタック(keyword→preview、tag→category→set、log→user)
  • 先頭同士は Protocol が衝突するので、スタック同士も直列マージが安全

後続は明示の順にしました。

#38 user_update#39 page_delete のアーカイブ掃除#40 export#40 import

import は安全ゲート(confirm: true、既定 draft、サイズ上限)がいるので最後にします。export と import を 1 PR にはしません。

「積む」と「後続」を混ぜない

これが一番整理で効きました。

種類 意味
今やる この親の完了条件 P1/P2、README/AGENTS ラップアップ
後続 今の親から切ったが、本体待ちではない user_update、page のファイル掃除、import/export
積む(P3) 技術的に不可能ではなく 今はやらない サイト CRUD、Stats、backup、migrate_*
NOT_PLANNED 必要なら再起票。親の積むリストに載せない ロール grant/revoke、テーマ、プラグイン

P3 は「できなかった」ではありません。サイト削除はテナント破壊、Stats は GA 未設定で失敗する、backup は restore なし巨大ファイル、移行は専用ツールを作らない、という 判断です。

後続は P3 と別枠です。親 #26 の「積む」に混ぜると、「#26 が開いている=まだロードマップ未完」が終わらなくなります。

実際の操作は次のとおりです。

  • 後続 3 件を起票(#38〜#40)
  • ラップアップ(#41 docs、#42 AGENTS.md)は #26 に残す
  • P3 と後続を新親 #44 検討中 のサブ issue にする
  • #41/#42 の PR が main に入ったら #26 を閉じる

GitHub のサブ issue は本文リンクではない

関連: 親 #26 と本文に書いただけでは サブ issue になりませんparent は null のままです。

REST は issue number ではなく database id を integer で渡します。文字列だと 422 になります。

起票したらすぐサブ issue API で付けます。あとから「なってる?」と確認することになりました。

意図的に外したものは、issue を読まないと危険

「今はやらない」を全部スキップしてよいわけではありませんでした。

  • 積んだ方がよい: #6 の import/export(後続と書いて CLOSED のまま)、#5 の page_delete 後の孤立 HTML
  • 積まなくてよい: grant/revoke、ログ書き込み、template_previewpage_idpermutate_folders、widget 専用 CRUD
  • 必要なら別 issue: user_update(#10 の必須ツール一覧に無かった)

親に「積まなかった理由」をコメントしておかないと、数週間後に「なぜログ write が無いのか」が issue から消えます。

ドキュメントの切り方

README にツール 50 件超を置くと、インストール手順が埋もれます。

  • README: インストール、Apache、トークン、クライアント、prove、リンク
  • docs/tools.md: 何ができるか、権限、警告
  • docs/guides/: 人間向け「記事を作る」「CT を作る」
  • docs/developer-onboarding.md: 人間の開発者向け
  • AGENTS.md: エージェント向け(触る場所、P3 を勝手に進めない)
  • Claude Skill (#23): まだ OPEN。人間ガイドの要約を AI コンテキストに載せる想定

正本は人間向けガイドです。Skill はコピー先で、tools.md は引数と権限の正本になります。AGENTS.md を開発者オンボーディングの代わりにはしません。

マージと Stacked Pull Requests

並列で実装すると、PR は増えます。困るのは GitHub 上で 全部 main 向けに見えて、依存順が分からなくなることです。

Stacked pull requests(public preview) は、大きい変更を短い PR の列にする仕組みです。各 PR は下の層を base にします。レビューは層ごとで、マージは下から、またはスタックごとに行います。公式アナウンスは GitHub Changelog(2026-07-30)

今回効いた点は次のとおりです。

  • P1 は Folder → Page → TemplateMap → Widgetset。下をマージすると上が追従しやすい
  • P2 の 3 スタック、後続の #46→#48→#49→#50 も同じ
  • 並列実装で起きたコンフリクトは、同じファイルを 3 本が main から同時に変えるから起きる
  • Stacked の順でマージすると、2 本目以降は「すでに入った兄弟」ではなく「自分の下の層」との差分になる。スムーズだった
  • 逆に、スタックを無視して #32 と #31 を両方 main に向けたまま交互にマージすると、README が毎回衝突する

#48 をマージしたあとの実スタックがこれです。下から main → #46(Merged)→ #48(Merged、current)→ #49 / #50(Ready)となります。

GitHub の Stacked PRs。#46←#48←#49←#50。#48 マージ後で current が page_delete

公式の「1 クリックで下の層までまとめてマージ」は、ブランチ保護と Checks が層ごとに付く前提です。こちらはコンフリクトが出た層だけ origin/main を feature にマージして通常 push しました。force-push しない方針と両立します。

エージェントへの指示も「独立 PR を default branch から」より、依存が本物ならスタックと書いた方が事故が少なくなりました。

並列開発で起きたトラブルと対処

GitGuardian は HEAD だけでなく PR 内の全コミットを見る

t/user_tools.t のダミーパスワードが Generic Password になりました。HEAD を changeme にしても、初回コミットに残っていると Checks は赤のままです。

対処としては、明示承認のうえで 2 コミットを 1 つに squash し、--force-with-lease を使いました(main ではない feature ブランチです)。実クレデンシャルではなかったのでローテーションは不要でした。

教訓としては、テストの秘密っぽい文字列は最初から changeme にすることです。スキャナーは履歴も見ます。

コンフリクトは README が本命

コードの自動マージは意外と通ります。人間が直すのは権限注記の箇条書きと、テストスタブのメソッド追加です。両側のツールを残すのが正解で、片方を取るのは事故になります。

サブエージェントのタイムアウト

worktree 解決で 30 秒タイムアウトしました。同じ指示で打ち直して通っています。親は「失敗した子の仕事を自分でやり始めない」で、打ち直すのが正解です。

タグは v を揃える

リモートに 0.4.2v0.1.0 が混在していました。同じコミットに v0.4.2 を打ち、旧タグと Release を付け替えています。main HEAD の版(config.yaml 0.7.0)に v0.7.0 を打ちました。

並列セッションの数字

親チャットは 2026-08-14 21:30 JST に始まっています(transcript の先頭)。P1 実装から v0.7.0 公開(08-15 08:03 JST)まで、時計のうえでは約 10 時間半です。中身は夜の実装塊(21:30〜23:46)と翌朝のラップアップ(07:23〜08:03)で、そのあいだは #43 のマージ待ちが長くなっています。

時刻の取り方は次のとおりです。

  • PR の作成・マージは GitHub の createdAt / mergedAt(UTC)を JST にしています。ここは正確です
  • エージェントの所要は、指示の timestamp と transcript ファイルの最終更新から出しています。終了時刻は分単位の目安です
  • prove の件数は各ストリームが報告した値です。スイート全体の合計ではありません(同じ folder.t を何度も数えるためです)
  • +/- 行は各 PR の GitHub 差分です。スタックなら base との差分なので、層を足すと実装量の目安になります
並列ストリーム 内容 期間の目安(JST) PR テスト(prove 報告) 備考
P1 実装 Folder / Page / TemplateMap / Widgetset 08-14 21:30〜21:45(約 15 分) まだ無し 6 files / 324 tests PASS worktree y4vv。内部で 3 本(21:35 起動)
P1 PR 分割 #27→#30 スタック エージェント 21:50〜22:02。PR 作成 22:00〜22:02、マージ 22:49〜22:52 4(#27〜#30) 分割時は prove を再実行していない オープン約 50 分はほぼ CI 待ち
P2 3 スタック keyword→preview、tag→category→set、log→user コーディネータ 22:07〜22:36。ワーカー 22:11〜22:35。PR 作成 22:17〜22:35、マージ 22:54〜23:17 7(#31〜#37) スライスごと(下表) 先頭同士が Protocol / README で衝突
ラップアップ README→docs、AGENTS.md #43: 23:40〜23:46 作成、翌 07:08 マージ。#45: 07:23〜07:28 #43 #45 ドキュメントのみ #43 は夜作成・朝マージ
後続ツール #38→#39→#40 export→#40 import エージェント 07:41〜07:52(約 11 分)。PR 07:44〜07:59 #46 #48 #49 #50 78 / 101 / 25 / 54 直列スタック。オンボーディングと同時起動
オンボーディング 人間向け docs(#22) エージェント 07:41〜07:46(約 5 分)。PR 07:46〜08:00 #47 なし 後続と同じ 07:41 に親から並列起動

P2 の prove はストリームごとにこう報告されていました。

PR スライス prove
#31 keyword LIKE 4 files / 138
#32 log 読み取り 当該 72。周辺込み 8 files / 396
#33 tag rename/delete 7 files / 389(P1 テストを含む)
#34 entry_preview 4 files / 157
#35 記事カテゴリ write 240(category / folder / tag / page)
#36 user 管理 3 files / 133
#37 category set category_set / category_write / folder / CT が PASS(件数は transcript に無し)

後続とオンボーディングの重なりは、エージェント実働で 約 5 分でした(07:41〜07:46。そのあと後続だけが 07:52 まで動いています)。PR が同時に開いていた時間は 約 13 分です(#47 の 07:46〜08:00 と、#46〜#50 の 07:44〜07:59)。壁時計では docs を書いているあいだに 4 PR が進んだ、で合っています。

GitHub 上のこの波(#27〜#37, #43, #45〜#50)は 18 PR です。差分の合計は約 +15,295 / −611(スタックの層を足した値)でした。v0.7.0 は 08-15 08:03 JST に公開しています。

スピードと費用感

上の表が「速さ」の中身です。

短かったもの(エージェント実働)

  • P1 4 機能の実装: 約 15 分(モジュール並列、配線は直列)
  • P1 の 4 PR 切り出し: 約 12 分
  • P2 7 PR: 実装〜作成まで約 30 分(最大 7 worktree)
  • 後続 4 PR: 約 11 分(中は直列)
  • オンボーディング 1 PR: 約 5 分

長かったもの(並列にできない)

  • P1 スタックのマージ: 作成から約 50 分(CI)
  • P2 マージ: 最後の作成 22:35 から最後のマージ 23:17 まで約 42 分。コンフリクトで origin/main を取り込み直した
  • #43: 作成からマージまで約 7 時間(夜→朝)
  • GitGuardian の履歴 squash、方針確認、CodeRabbit の 1 件ずつ

Claude と同じ「issue を分解してエージェントに実装させる」をやると、こちらでは すぐリミットに当たりました。Grok はこの親セッションを夜から朝まで続けられています。差として確かなのはそれだけで、モデル単価の比較はしていません。Claude 側のリミット画面は今回撮っていません。

トークン量は Cursor の Usage(2026-08-15 のみ)で見えました。合計 7.3M です。内訳は Included 7.3M、On-demand 0。モデル別は cursor-grok-4.6-high が約 4.5〜4.7M、cursor-grok-4.6-medium が約 2.6〜2.8M でした。ドルは出しません。New Relic ではこの作業の費用は取れませんでした。

Cursor Usage。2026-08-15 の Included 7.3M、On-demand 0。high と medium の内訳

リクエスト表では、同じ分に複数行が並びます。並列バーストです。1 行で 225.8 万トークン(high)もあります。

同日のリクエスト表。Included。同じ時刻に複数行。high で 225.8 万の行

プラン側の枠は Cursor Pro の Included in Pro です。Cursor Models(Grok と Composer)は 17% used、Other Models は 9% used でした。Cursor Models を使い切ったあとは Other Models の枠か on-demand に乗ります。Other Models には少なくとも $20 の API usage が含まれる、と画面に書いてあります。どちらもまだ大半が残っています。7.3M トークンを積んでも、Grok 側の枠は余裕、という話の根拠です。

Cursor Pro の Included in Pro。Cursor Models 17% used、Other Models 9% used

並列は壁時計を短くします。合計トークンは増えます。親がコーディネータに徹すると、同じ調査を 3 回やらなくて済む、という話は残ります。

手順の再利用と、ストリームごとの出力量の表は Zenn に置きました。こちらは素材と PR 表です。7.3M は 8/15 の1日分で、P1 本体(8/14 夜)は含みません。

https://zenn.dev/redamoon/articles/article52-issue-based-grok-cursor

次に記事にするときの構成案

公開用に削るなら、この 3 本立てで足ります。

  1. Grok + Cursor のマルチタスクで MT プラグインを並列実装した
  2. issue の親・積む・後続を分けないとロードマップが閉じない
  3. 並列 PR のコンフリクトは Stacked PRs の順でマージすると楽

コード片は最小にします。リンクは #26、#44、Stacked PRs の Changelog、リポジトリです。スクショはスタック UI と Cursor Usage(8/15)を置きました。Claude リミット画面はありません。

残っていること(記事の「いま」)

  • P3 は検討中のまま(#44)
  • Claude Skill(#23)は未着手
  • 人間向けオンボーディング #47、後続 #46/#48/#49/#50 は 08-15 朝にマージ済み。v0.7.0 公開済み
  • Cursor 用 Skill の issue は無い

自分用チェックリスト(次のリポジトリでも)

  • 親 issue に今やる / 後続 / 積む / やらない を先に書く
  • 実装 PR は機能単位。共有ファイルがあるならスタック
  • エージェントには worktree を分ける。dirty な木を共有しない
  • 独立実装は並列、Protocol 配線とマージは直列
  • サブ issue は API で parent を付ける
  • テストに秘密っぽい文字列を置かない
  • README にカタログを増やさない。docs へ逃がす
  • タグは最初から v
  • リミットが浅いモデルでは「巨大 1 エージェント」より「短い指示の並列」より先に、作業を日をまたがないサイズに切る