agent-sync — 単一プロジェクト、複数エージェント、競合なし
2つのプレーンと、それらの間の1つのルール:
Gitが記録プレーンです。クラウドが調整プレーンです。 永続的に残す必要がある事実は、まずGitに書き込まれ、クラウドから参照されます。 現在誰が何をしているかに関する事実はクラウドに存在し、期限切れになります。
いかなるクラウドオブジェクトも、永続的な事実の唯一の保存場所ではありません。以下のすべては、複数のエージェントが同時に書き込む場合でも、この原則を維持するために存在します。
4つの落とし穴 — これらを最初に読んでください
1. 知識ベースはリースを決定しません。 それはできません。1つのOutlineドキュメントへの12の同時追加は12の成功を返しましたが、残ったのは3行でした。排他性は、実際のcompare-and-swapを備えたものから得られます。プレーンは記録を運ぶだけで、それ以外は何も運びません。詳細な測定値は references/lease-protocol.md にあります。
2. 自分がどのリースを持っているかを把握し、そのように伝えてください。 leaseBackend: "local" はアトミックファイル作成です — 1つのファイルシステム上のプロセス間では排他的ですが、マシン間ではアドバイザリです。leaseBackend: "git" はrefをプッシュし、リモートのnon-fast-forward拒否がcompare-and-swapとして機能します — マシン間で排他的です。acquire はどちらかを出力します。偽装されたリースはリースがないよりも悪いです。他のエージェントがチェックを停止するからです。
acquire はクレームをロードマップにも書き込み、release はそこにあったものを正確に復元します — 1行、1セル、あいまいな場合は拒否され、ラウンドトリップ後は git diff が空になります。claimTags を設定したりタスクをクローズしたりする前に references/roadmap.md を読んでください。クローズは作業に関するステートメントであり、あなたのもののままです。
ブランチ上で作業してください。統合ブランチは誰か他の人の安定したベースです。 acquire はクレームをそのブランチにのみ書き込みます。他のブランチでは、ホルダーは調整プレーンに留まり、status は誰もあなたのブランチをフェッチしなくても、すべてのエージェントにそれを表示します。ブランチにコミットされたクレームは、マージされるまで見えず、共有ロードマップを両方のブランチが編集するファイルに変えます。merge で作業を統合します。競合は何かに触れる前に git merge-tree によって計算され、存在する場合は名前が付けられ拒否され、マージは docs/MERGES.md に記録され(最近の日付は全文、古いものは書き込み時に圧縮)、--key リースが解放されます。merges は、次のエージェントに、自分が離れている間に何が着地したかを伝えます。マージする前に references/branching.md を読んでください。
3. フックはClaude Codeにのみ存在します。 他の場所では、ガードされた編集をブロックするものは何もありません。自分で guard を実行し、その実行を ungated として記録してください。プロジェクトが保護されていると、実際には保護されていないのに説明しないでください。
4. 寛大にパースし、読み取れないログを失われた競争とは決して呼ばないでください。 ストアはあなたが書いたものを書き換えます — Outline は - 箇条書きを * に変えます。- を出力し、-/*/+ を受け入れ、エントリ形状のもので失敗したものをカウントし、パース不能が2%を超えた場合は大声で失敗してください。存在しないホルダーを名指しする lost を報告することは、真実が読み取れない場合です。静かなプリフィルターに注意してください。正規表現の前の continue は、それらを公開するために構築されたカウンターから悪い行を隠します。
これを任意のプロジェクトに導入する — 全体のチェーン
scaffold → ドキュメントアーキテクチャを作成する(存在しない場合のみ)
adopt → リポジトリを読み取り、設定を提案し、何も書き込まない
init → 承認された設定 + git無視されたenvファイルを書き込む
(オペレーターがトークンを貼り付けます — あなたは決して行いません)
reconcile --set-baseline → 履歴をカウントされたバックログにする(1回のみ)
setup → このプロジェクトの配線を説明するスナップショットを生成する
check → 全体を検証する。正常でない場合は非ゼロを返す
check はスキルを自己完結型にするものです。 何も保護しないルール(存在しないものを指すレジスタ、ガードグロブ、クレームパターン、ゲート、ミラーソース)、欠落した資格情報、gitで追跡されている envファイル(ここで唯一回復不可能な間違い)、古いまたはリンクが切れたスナップショット、ベースラインのないレジスタがある場合、セットアップを正常と呼ぶことを拒否します。それぞれに名前を付けます。これらすべてが、このツール自身の導入中に実際に失敗しました。
導入後、設定変更後、およびCIで check を実行してください。
scaffold は決して上書きしません。 割り当て行とスナップショットを指す AGENTS.md を持つ決定レジスタをシードし、既存のファイルには一切触れません。導入時にプロジェクト自身の規則を書き換えるツールは、何もしないツールよりも悪いものです。
既存のプロジェクト: adopt から始めてください
init の前に adopt を実行してください。リポジトリを読み取り、見つけたもの — IDレジスタ、レジストリファイル、ゲート — と、あなたのために決定することを拒否する決定事項を出力し、設定を提案します。
python3 "$SKILL_DIR/scripts/agent_sync.py" adopt
レジスタとガードされたファイルを最初にオペレーターと確認してください。間違ったファイルを指すレジスタは、以降のすべてのチェックを間違って自信満々にし、共有ファイルを見逃すガードリストは、競合が発生する唯一の場所を保護されないままにします。サブモジュールでは、レジスタを宣言しません。決定は親リポジトリに属します。その後、上記のチェーンを init から実行してください。
プロジェクトでの最初のコマンド: init
初期化されていないプロジェクトに対して他のコマンドを決して実行しないでください。 init は、ストレージに関する質問が行われ、回答され、一度だけ書き留められる場所です。
チャットでこれら2つのことをオペレーターに尋ねてください — 推測したり、デフォルトを選択したりしないでください:
-
調整状態はどこに置くべきですか?
- 知識クラウド (
outline) — マシン間での共有レコード、認識、ボード。リースを決定しません。そこにあるものは何もできません(落とし穴1)。 - またはローカルファイル (
fs) — 資格情報は不要で、別のマシンのエージェントからは見えません。共有認識なし、クロスリポジトリシグナルなし、共有ボードなし。
リースは
leaseBackendによって個別に決定され(落とし穴2)、gatedはその選択に従い、記録プレーンには決して従いません。記録プレーンが示唆するより強いものではなく、実際に持っている保証を報告してください。 - 知識クラウド (
-
クラウドの場合: インスタンスURL。 URLは設定であり、シークレットではないため、書き込んでも構いません。トークンはシークレットです — チャットで尋ねたり、読み返したり、自分で配置したりしないでください。
次に、オペレーターの回答を指定して実行します:
python3 "$SKILL_DIR/scripts/agent_sync.py" init --backend outline --url https://<their-instance>
python3 "$SKILL_DIR/scripts/agent_sync.py" init --backend fs
init は .claude/agent-sync.json(形状、コミット済み)を書き込み、キーと空のトークン行を持つ .env.agent-sync(ID、モード600)を書き込み、.env.agent-sync と .agent-sync/ を .gitignore に追加し、オペレーターが自分で行わなければならないこと — 自分のインスタンスでトークンを作成し、その1行に貼り付けること — を正確に出力します。--force なしでは、既存の設定やenvファイルを上書きすることはありません。
これらの最後の指示をオペレーターにそのまま伝えてください。トークンをファイルに格納するのはオペレーターのステップであり、設計はそれがオペレーターのものであることに依存しています。
その後、各セッションの前に
python3 "$SKILL_DIR/scripts/agent_sync.py" status
冪等です。検査、修復、報告、そして正確に1つの次のアクションを指名します — そして check の判定を運ぶため、すべてのセッションで実行されるコマンドとセットアップを検証するコマンドが、1つのプロジェクトについて2つの異なる答えを返すことはありません。
それが出力する2つの認識セクションを読んでください — それらが要点であり、飾りではありません。
- 現在このプロジェクトで作業している他の実行。 誰が何を保持しているか、今この瞬間。それらを引き受けず、それらがカバーするファイルを「ちょっと見る」こともしないでください。見えないリースはあなたをブロックします。見えるリースはあなたを調整させます。
- 前回見てから新しく追加されたもの。 あなたが離れている間に着地した、クロスリポジトリの依存関係の移動。移動した依存関係は、計画していたことをブロック解除するか、無効にする可能性があります。このリストは実行ごとにウォーターマークが付けられるため、実際に何かが変更されるまで静かに保たれます。話すとき、それは重要です。
このブロックをスキップするエージェントは、他の誰かが行っている作業を再導出し、1時間前に変更された依存関係の状態に基づいて行動します。
status が他に決定すること: 資格情報なし → 縮退モード、報告され、続行します(エラーではなく、より小さいモード)。task-pipeline が存在しない → インストール行を出力して停止します。代替フローを即興で作成しないでください。それらのステージがなければ、バインドするものが何もありません。
npx sshlg-skills install
コマンド
| コマンド | 機能 |
|---|---|
init | 最初に実行。 状態がどこにあるか尋ね、設定 + git無視されたenvファイルを書き込み、オペレーターのステップを出力 |
status | 検査、修復、報告、1つの次のアクションを指名 |
bootstrap | クラウドコンテナを作成し、envファイルに貼り付けるIDを出力 |
acquire <KEY> | タスクIDのリースを取得。won または lost <holder> を出力 |
renew <KEY> | リースを延長。PostToolUse フックが自動的に実行 |
release <KEY> | リースを返却。失敗時も含め、必ず実行 |
reserve <REG> | レジスタ内の次のIDを予約(DEC、OQ、DEPなど)。IDを出力 |
release-id <REG> <ID> | 結局gitに書き込まなかったIDを返却 |
journal <text> | この実行のジャーナルに1行追加 |
record <text> | 実際に構築したものを追加 — --decision DEC-…、--files a,b |
reconcile | 意図(git)と実際の構築(クラウド)を調整。プロジェクトごとに --set-baseline を1回 |
signal <DEP-ID> <state> | クロスリポジトリ依存関係を移動: filed/accepted/delivered/closed/refused |
guard <path> | この実行がそのパスに書き込んでもよいかどうかを回答。終了コード0 = はい、2 = いいえ |
board | 共有ボードとこのリポジトリのページを再生成。--mirror は設定されたgitドキュメントもプレーンにレンダリング |
whoami | この実行のIDと保持しているリースを出力 |
setup | このプロジェクトがどのように配線されているかの生成スナップショットをエージェントが読めるように書き込み |
adopt | 既存のプロジェクトを検査し、設定を提案 — 何も書き込まない |
merge | このブランチを統合: ローカルターゲットをfast-forward、競合は何かに触れる前にチェック、マージログを書き込み、--key リースを解放。--summary、--dry-run、--push |
merges | ブランチ上にいる間に着地したもの。--all は圧縮された末尾を含む |
check | セットアップ全体をエンドツーエンドで検証。正常でない場合は非ゼロ |
scaffold [--full] | 不足しているもののみを作成し、存在するものには決して1行も上書きしない。--full は質問レジスタ、インデックス、依存関係ボード、エンティティレジスタを持つデータモデル、ドキュメントゲートもシード |
finish [--gates] | 作業は完了したか — すべてのリポジトリがクリーンで、プッシュされ、指摘され、保持されているリースがない。check はプロジェクトが正しく配線されているかどうかを回答。これはあなたが完了したかどうかを回答 |
$SKILL_DIR はこのスキル自身のディレクトリです: Claude Codeプラグイン下では ${CLAUDE_PLUGIN_ROOT}/skills/agent-sync、それ以外では ~/.agents/skills/agent-sync。セッションごとに1回解決して再利用してください — パスを推測しないでください。すべてのコマンドはプロジェクトルートから .claude/agent-sync.json を読み取り、リストされたもの以外の引数は必要としません。
セッションごとの1つのID、およびその決定方法
リースは、2つのエージェントが2つのIDを取得した場合にのみリースです。ここでは順序が重要であり、両端で問題が発生しました。CLAUDE_SESSION_ID のみからIDを導出すると、1つのセッションが2つのIDを持つことになりました — 1つとして取得し、自身のガードによって別のものとして拒否されました — また、チェックアウトごとに1つのIDを保持すると、2つのセッションが1つのIDを持つことになり、これはさらに悪いです。2番目はサイレントです。両方のセッションが取得し、両方ともガードされ、release は呼び出し元が決して持っていなかったリースを取得します。
順序は: AGENT_SYNC_RUN_ID · CLAUDE_SESSION_ID · このシェルを開始したセッション · 共有。
3番目が重要なのは、プレーンなシェルコマンドにはセッションIDがなく、フックにはあるためです。したがって、SessionStart は .agent-sync/sessions/<CLI pid> に、それが認識しているセッションをスタンプし、後続のコマンドは自身のプロセス祖先をスタンプされたpidまでたどることで自分自身を見つけます。なぜコマンドライン解析ではないのか: references/earned-rules.md。
4つのいずれも確立できない場合、実行はそれを伝えます — 「このIDは、このチェックアウト内の他のセッションと共有されています」 — 共有エントリを分離として提示する代わりに。
クレーミング — 重要な形状
acquire → 作業を行う → release
release をスキップしないでください。失敗時も含めてです。放棄されたリースは、TTLが期限切れになるまでタスクをブロックし、次のエージェントは「進行中」と「1時間前にクラッシュした」を区別できません。
リースはクレームではありません。 リースは今誰が保持しているかを示し、期限切れになります。永続的なクレームはgit内のタグであり、acquire によって書き込まれ、release によってクリアされます。1つの事実、1つのホーム — 所有権を記録する3番目の場所をでっち上げないでください。
取得、期限切れ、盗取、またはID割り当てを変更する前に、references/lease-protocol.md を読んでください。
ガードされたファイル
設定には、複数のエージェントが書き込むレジストリファイルがリストされています。編集する前に:
python3 "$SKILL_DIR/scripts/agent_sync.py" guard docs/DECISIONS.md
終了コード2 はこの実行に関するものです: リースを保持していません — 他の誰かがそのファイルを保持しているわけではありません。1つのリースですべてのガードされたファイルをカバーします。1つ保持するか、まったく書き込まないかのどちらかです。拒否は、他の実行とそのキーを指名します。なぜなら、「r-xがリースを保持している」がパスの横にあると、「r-xがこのファイルを保持している」として繰り返されるからです。とにかく編集しないでください。「1行だけ修正する」こともしないでください。上書きされた決定は、決定とまったく同じように見えます。
Claude Codeの PreToolUse フックがこれを自動的に実行します。他の場所では何も実行しません。
IDの予約
「次の空きID」行を読むことは、それを予約することではありません。2つのエージェントが同じ番号を読み取り、両方ともそれを使用します。
python3 "$SKILL_DIR/scripts/agent_sync.py" reserve DEC # → DEC-0216
割り当てはマージされたログ上の位置に基づきます — すべてのシャード、決してこの実行のものだけではありません — そのため、すべてのエージェントが同じ答えを計算します。予約したがgitに書き込まなかった場合? release-id を使用してください。さもなければ、その番号はボードがリークとして報告する穴になります。
ログ内のものは決して編集または削除されません
ログは順序通りに再生されるため、編集は他のエージェントがすでに行動した結論を静かに書き換えます。追加によって修正してください: リースを解放し、未使用のIDを release-id し、間違ったas-builtエントリを後のもので置き換えます。生成されたページは唯一の例外であり、agent-sync:generated マークを失ったものは…
[翻訳のため省略]