概要
複数のMacを使い分けていると、マシンを切り替えるたびに各リポジトリでgit pull/git pushするのが面倒になる。Claude Codeにはskill(手順書)とagent(サブエージェント)という仕組みがあり、これを組み合わせて/globalsyncと打つだけで9つのリポジトリを並列に同期してくれる仕組みを作った。そのまとめ。
問題: 複数マシンでのリポジトリ同期
自分は複数のMacを使い分けて作業している。仕事用・個人用あわせて9つのgitリポジトリを日常的に使っていて、マシンを切り替えるたびに各リポジトリでgit pullしてgit pushする必要がある。
9つのリポジトリに対して毎回これをやるのは面倒だし、忘れる。例えば、あるマシンで設定ファイルを更新して、別のマシンでpullし忘れて古い設定のまま作業を始める、みたいな状況を想像してみる。地味だが確実にストレスになる。
Claude Codeのskillとagent
Claude Codeにはskillとagentという仕組みがある。
skillは、Claude Codeに特定のタスクをやらせるための手順書みたいなもの。/globalsyncのようにスラッシュコマンドで呼び出すと、skillに書かれた手順に従ってClaude Codeが動く。知識やワークフローの定義。
agentは、特定のタスクを自律的にこなすサブプロセス。Task toolでspawnすると、独立したプロセスとして動いてくれる。skillがオーケストレーターだとすれば、agentはワーカー。
この2つを組み合わせると「skillが全体の段取りを指示し、agentが個々の作業を並列に実行する」という構成が作れる。
対象リポジトリ
同期対象の9つのリポジトリは以下の通り。
仕事用リソース(~/repos/w/配下):
cg— CodeGrid執筆用のDocusaurusサイト。執筆ルールやリファレンスをまとめているesa— esa執筆用のDocusaurusサイト。記事の下書きやルールを管理message— メール・Slackなどのメッセージ下書きヘルパー。Docusaurusで構築zpaper— 個人ブログ(Next.js)+ 執筆ルールのDocusaurusドキュメントサイト
スタンドアロン:
~/.claude— Claude Codeの設定、skill、agent、コマンドなどの格納場所
個人用リソース(~/repos/p/配下):
claude-resources— Claude Code設定の公開リポジトリ。コマンド・skill・agentなどを共有dotconfigetc—~/.config配下の管理対象(ghosttyなど)をシンボリンクで管理dotconfignvim— Neovim/VimRの設定ファイル群dotfiles—.zshrc、.gitconfigなどのdotfilesを複数Macで共有
repo-syncer agent
まず作ったのが「repo-syncer」というagent。1つのリポジトリに対してgit同期を行うサブエージェント。
ファイルは~/.claude/agents/repo-syncer.mdに置いている。
---
name: repo-syncer
description: Git pull-push sync agent for a single repository. Handles fetch, pull with rebase, conflict resolution, and push.
model: sonnet
color: green
---処理フローはこういう感じ。
git fetch --allでリモートの最新状態を取得git statusで現在の状態を確認(ブランチ、未コミットの変更、ahead/behind)- 未コミットの変更がある場合は
git stashで退避 git pull --rebase origin <current-branch>でpull- stashした変更があれば
git stash popで復元 git push origin <current-branch>でpush- 結果をレポート
コンフリクト解決の方針
コンフリクトが発生した場合の方針は以下の通り。
- 軽微なコンフリクト(異なる箇所の編集)は自動解決してスムーズに進める
- 同じ行の編集など判断が必要なものはrebaseをabortしてユーザーに確認を求める
- 変更を暗黙的に捨てることは絶対にしない
最後のポイントが一番重要で、git同期の自動化で怖いのは「知らないうちに変更が消えていた」という事態。repo-syncerは判断に迷ったら必ず止まるようにしている。
modelにSonnetを指定する
agentの定義でmodel: sonnetを指定している。git操作のような定型的な処理にはSonnetで十分で、Opusを使う必要がない。コストの最適化としても有効。
globalsync skill
次に作ったのが「globalsync」というskill。9つのリポジトリそれぞれに対してrepo-syncerをspawnするオーケストレーター。
ファイルは~/.claude/skills/globalsync/SKILL.mdに置いている。
---
name: globalsync
description: Sync all personal repos across machines via git pull & push. Use when: (1) User says 'globalsync', 'sync repos', 'pull push all', (2) User wants to sync their daily resources across machines, (3) User starts or ends a work session and needs repos up to date.
allowed-tools: Bash, Read, Task
---skillの中身は、対象リポジトリのリストと、それぞれに対してrepo-syncerをspawnする手順が書いてある。Claude Codeはこのskillの指示に従って、Task toolを使い9つのrepo-syncerを1つのメッセージで並列にspawnする。
アーキテクチャ
全体の構成はこういう形になっている。
globalsync (skill) ─ オーケストレーター
│
├─ Task(repo-syncer) → ~/.claude
├─ Task(repo-syncer) → ~/repos/w/cg
├─ Task(repo-syncer) → ~/repos/w/esa
├─ Task(repo-syncer) → ~/repos/w/message
├─ Task(repo-syncer) → ~/repos/w/zpaper
├─ Task(repo-syncer) → ~/repos/p/claude-resources
├─ Task(repo-syncer) → ~/repos/p/dotconfigetc
├─ Task(repo-syncer) → ~/repos/p/dotconfignvim
└─ Task(repo-syncer) → ~/repos/p/dotfiles
全エージェント完了後 → サマリーテーブルを表示skillがオーケストレーター、agentがワーカーという役割分担。9つのrepo-syncerは並列に動くので、逐次実行するよりかなり速い。
実行結果
実際に/globalsyncを実行した結果がこれ。
| Repo | Status | Details |
|---|---|---|
| ~/.claude | OK | Already up to date |
| w/cg | OK | Pulled 1 commit, 7 uncommitted files preserved |
| w/esa | OK | Already up to date, 1 uncommitted file preserved |
| w/message | OK | Pulled 1 commit, 1 uncommitted file preserved |
| w/zpaper | OK | Already up to date |
| p/claude-resources | OK | Already up to date |
| p/dotconfigetc | OK | Already up to date |
| p/dotconfignvim | OK | Already up to date |
| p/dotfiles | OK | Pulled 3 commits |
9リポジトリすべてがコンフリクトなく同期完了。未コミットの変更があるリポジトリ(cg、esa、message)ではstash→pull→stash popの手順で変更が保護されている。全体の結果がサマリーテーブルで出てくるので、何が起きたか一目でわかる。
skill + agent構成のパターン
今回の/globalsyncで使った「skillがオーケストレーター、agentがワーカー」という構成は、他の場面にも応用できるパターンだと思う。
ポイントをまとめると以下の通り。
- skillに全体の段取りと対象リストを書く
- agentに1つの作業単位の処理を書く
- skillからTask toolでagentを並列にspawnする
- agentのmodelは処理内容に応じて選ぶ(定型処理ならSonnetで十分)
- 判断が必要な場面ではagentが止まってユーザーに確認を求める設計にする
繰り返し作業で、かつ並列化できるものがあれば、このパターンが使えそう。