contribute-skill
ローカルで改修した `skills/<skill-name>/` を upstream リポジトリ (Fandhe-AI/agent-cli-skills 等) へ PR として投稿する。`skills-lock.json` の `source` を読み、`Fandhe-AI/` 以外への push は安全弁で中止。clone → 反映 → セキュリティチェック → ブランチ作成 → push → `gh pr create` を実行。マージ後は sync-skills-lock で hash 更新。「スキルを upstream に貢献」「外部リポジトリに PR」などで使用。
By fandhe-ai · 664 installs
npx skills add fandhe-ai/agent-cli-skills --skill contribute-skill
Source repository · Upstream listing
contribute skill
ローカルで改修した skills/<skill name / を、 skills lock.json に記録された upstream リポジトリへ PR として投稿します。
前提条件
gh CLI がインストールされ認証済みであること(対象 org への push / PR 権限が必要)
対象スキルが skills lock.json に登録されていること
対象スキルのローカル改修が最新のコミットに含まれ、作業ツリーが clean であること
責務の分離
create pr : 現在のリポジトリ内でカレントブランチから base へ PR を作成する
contribute skill : 別リポジトリ(upstream)へ clone → 変更反映 → push → PR 作成を行う
外部リポジトリ貢献は clone / path 変換 / 異なる認証境界が関わるため、別スキルとして分離しています。
フロー
Step 1: 引数を検証する
引数が空の場合はパス解決に進まず、 skills/ ・ .agents/skills/ ・ .claude/skills/ (実ディレクトリのみ。symlink は実体側の候補に現れるため除外)の候補一覧を表示して終了します。Claude はその一覧をユーザーに提示し、スキル名を選んでもらってから再実行を促してください。後続の Step では ${LOCAL SKILL DIR}/ を使ってローカルパスを参照します。
skills/ ・ .agents/skills/ ・ .claude/skills/ (実ディレクトリのみ。symlink は実体側でカウント)の 複数にディレクトリが存在する場合は中止 し、環境変数 LOCAL SKILL DIR に改修対象のパス( skills/<name ・ .agents/skills/<name ・ .claude/skills/<name のいずれか)を指定して再実行するよう案内します(silently に skills/ を優先しません)。環境変数 LOCAL SKILL DIR が設定済みの場合は、許可された3パスのいずれかであること・経路の全要素(中間の親ディレクトリ含む)が symlink でないこと・実在することを検証してから採用し、自動解決をスキップします。いずれにも存在しなければエラーで中止します。
Step 2: upstream を特定する
ルートの skills lock.json を読み、 skills.<SKILL NAME .source を取り出します。
source は正規化後の OWNER/REPO が ^Fandhe AI/[A Za z0 9. ]+$ に完全一致する場合のみ許可します(安全弁:見知らぬリポジトリへ意図せず push しないため)。 ../ を含むパストラバーサル・クエリ( ?x=1 )・フラグメント( frag )・余剰パスセグメント( /extra )を含む値は正規表現に一致せずエラーで中止します。検証は必ず .git 除去などの正規化の 後 に行います(正規化前に検証すると Fandhe AI/..git のような値が正規化後に別の値へ化けてすり抜けるため)。
sourceType が github 以外の場合も エラーで中止 します(GitHub 以外の source は本スキルの想定外であり、 gh repo clone / gh pr create が正常動作しないため)。
正規化後の REPO SLUG は以降の Step で gh repo clone ・ gh pr create repo に利用します。
Step 3: 変更内容を確認する
ユーザーに「この改修内容で upstream に PR を作ってよいか」を確認します。
Step 4: セキュリティチェック(必須)
create pr と同様に以下をレビューします。
認証・認可の実装漏れ
API キー・シークレットのハードコーディング
XSS の可能性(ドキュメントでも外部埋め込みが含まれる場合)
入力バリデーションの欠如
OWASP Top 10
問題があれば upstream 貢献を中止し、ユーザーに警告します。
Step 5: 変更を反映する
skills contribute.sh は upstream の gh repo clone から作業ディレクトリ( WORKDIR )の作成・反映までを自己完結で行います。手動での事前 clone は不要です(機械可読な CONTRIBUTE SKILL WORKDIR= 等の出力を Step 6 以降で唯一の正として使う契約に一本化しています)。
このステップは手順を個別に打鍵せず、必ず本スキル自身のスクリプト( skills contribute.sh )を実行してください。 同スクリプトには rm rf 前の symlink 境界検証(TOCTOU 対策込み)が実装されており、以下の断片だけを個別に実行すると検証が欠落します。
skills contribute.sh は upstream 側でスキルがどのパス構造に置かれているか( UPSTREAM SKILL PATH 。 skills lock.json の skillPath はローカル install パスであり upstream 内の配置ではないため使用しません)の判定と、 cp R の delete then copy 反映を内部で行う自己完結型スクリプトです。判定・反映のロジックは後述の参考コードのとおりです。
LOCAL SKILL DIR は Step 1 で解決した 貢献対象スキル ( $ARGUMENTS )のパスであり、本スキル(contribute skill)自身の配置とは無関係です。スクリプトの実行パスに LOCAL SKILL DIR を流用すると、貢献対象が contribute skill 以外の場合に存在しないパスを参照してしまいます。実行するスクリプト自身の配置は別変数 CONTRIBUTE SKILL DIR として、本スキル(contribute skill)自身のインストール場所から解決してください。
skills contribute.sh は呼び出し時のカレントディレクトリを貢献元リポジトリのルートとして LOCAL SKILL DIR ・ skills lock.json を探索し、内部で自分自身の gh repo clone と WORKDIR (clone 先)を新規作成します。手動での事前 clone は不要なため、実行直前にこの Step 内で ORIG DIR (貢献元ローカルリポジトリのルート)を捕捉しておいてください。スクリプトの標準出力最終行群が返す CONTRIBUTE SKILL WORKDIR=<path と CONTRIBUTE SKILL UPSTREAM PATH=<path を捕捉し、 WORKDIR および(後述の参考コードで示す判定ロジックの) UPSTREAM SKILL PATH はこれらの値のみを唯一の正として採用します(参考コードを個別実行して得た値は使用しません)。これにより Step 6 以降が参照する ${WORKDIR}/upstream と ${UPSTREAM SKILL PATH} は、スクリプトが実際に使った clone・実際に反映したパスと一致します。
以下は skills contribute.sh が内部で実行する処理( UPSTREAM SKILL PATH の判定・delete then copy)の参考コードです。上記のスクリプト実行によって既に完了しているため、個別に実行する必要はありません。
削除対象は必ず ${WORKDIR}/upstream/ 配下(clone 用の一時ディレクトリ)に閉じ、 UPSTREAM SKILL PATH が skills/<name ・ .agents/skills/<name ・ .claude/skills/<name の 3 形態以外なら rm rf の前に中止します。加えて中間パスの symlink 化・TOCTOU に対する実体パス検証を rm 直前に行います。新規スキル追加(宛先未存在)の場合も削除処理は無害にスキップされ、直後の mkdir p で作成されます。
Step 6: 差分を確認する
ユーザーに差分を見せ、内容が意図通りか確認します。
Step 7: ブランチ作成・コミット
git add "${UPSTREAM SKILL PATH}/" はパス指定 add のため、Step 5 の delete then copy で消えたファイルの削除( D )も含めて stage されます
Conventional Commits 形式
no verify は使用しない(pre commit フックを通す)
co author は付けない(ローカル規約に合わせる)
Step 8: push と PR 作成
repo には Step 2 で正規化した ${REPO SLUG} ( OWNER/REPO 形式)を渡します。URL 形式から OWNER/REPO への変換は Step 2 の case 文で完了しています。
body の <SRC REPO は上で取得した貢献元リポジトリの OWNER/REPO (origin 未設定時はディレクトリ名)に置き換えます(heredoc はクォート済みのため Claude が実値で埋める。特定リポジトリ名のハードコード禁止)。
Draft PR を作成する場合は draft を付けます(デフォルトはユーザー確認の上で決定)。
Step 9: PR URL を返す & 後処理案内
PR URL をユーザーに返す
「マージされたら /sync skills lock を実行して skills lock.json の computedHash を更新してください」と案内
作業用ディレクトリ $WORKDIR は残したまま(成否が確定するまで)
注意事項
SKILL NAME は kebab case のみ許可 : .. のような値によるパストラバーサルを防ぐため、空判定の直後・パス解決の前に ^[a z][a z0 9 ]+$ で検証する(security.md A03/A01)
skills/ ・ .agents/skills/ ・ .claude/skills/ の複数に実体が存在する場合は中止 :silently に skills/ を優先せず、環境変数 LOCAL SKILL DIR に改修対象パスを指定して再実行を求める。 LOCAL SKILL DIR は skills/<name ・ .agents/skills/<name ・ .claude/skills/<name の3パスのみ受理し(末尾要素・中間の親ディレクトリのいずれかが symlink なら実体側パスの指定を要求)、任意パス指定によるパストラバーサルを防ぐ。Step 5 で本スキル自身(contribute skill)の配置を解決する CONTRIBUTE SKILL DIR も同じ fail closed 方針を取り、 ${ORIG DIR}/skills/contribute skill ・ ${ORIG DIR}/.agents/skills/contribute skill ・ ${ORIG DIR}/.claude/skills/contribute skill の3候補のみ受理する(末尾要素・中間の親ディレクトリのいずれかが symlink なら実体側パスの指定を要求)。3候補のうち複数が存在する場合は silently にどれかを優先せず中止して環境変数 CONTRIBUTE SKILL DIR での指定を求める(LOCAL SKILL DIR とは非対称にしない)
source が Fandhe AI org 以外の場合は中止 :前方一致( Fandhe AI/ 等)ではなく、正規化( .git 除去等)後の OWNER/REPO が ^Fandhe AI/[A Za z0 9. ]+$ に完全一致するかで判定する。 ../ によるパストラバーサル・クエリ・フラグメント・余剰パスセグメントを含む値、および repo 名が . / .. になる値は中止し、意図しない外部リポジトリへの push を防ぐ
セキュリティ問題が見つかった場合は中止 :修正後に再実行
upstream の配置はクローンしたリポジトリのレイアウトで判定する : skills lock.json の skillPath はローカル install パス(例: .agents/skills/github docs/SKILL.md )であり、upstream リポジトリ内の配置ではない。 skillPath の dirname を UPSTREAM SKILL PATH に採用してはならない。判定順は skills/<name の存在 → .agents/skills/<name の存在 → .claude/skills/<name の存在 → スキルルート親ディレクトリの慣習( skills/ → .agents/skills/ → .claude/skills/ の順。新規スキルは個別パスが存在しないためこの親ディレクトリ判定で配置先が決まる)→ 最終デフォルト skills/ (より一般的な公開レイアウト)。全候補で assert no symlink components により経路の全要素( .claude 等の最上位親を含む)が symlink でない場合のみ採用し、 .claude 自体がリポジトリ外を指す symlink でも外部内容が upstream へコピーされない(fail closed。symlink 経由の実体は前段の実体側候補で検出される)
宛先は消してからコピーする(削除伝搬) : cp R は追加・上書きのみで削除を反映しないため、ローカルで削除したファイルが upstream 側に残存してしまう。 rm rf 前に UPSTREAM SKILL PATH が skills/<name ・ .agents/skills/<name ・ .claude/skills/<name のいずれかであることを case 文で検証し、それ以外の値なら中止する。加えて rm rf 直前に実体パス(symlink 境界・clone ルート配下チェック、cd P + 相対 rm による TOCTOU 対策)を再検証する。削除対象は必ず clone 用の一時ディレクトリ( ${WORKDIR}/upstream/ )配下のみに閉じ、それ以外のファイルには一切触れない。 Step 5 は必ず ${CONTRIBUTE SKILL DIR}/scripts/skills contribute.sh (本スキル自身の配置から別途解決したパス。貢献対象のパスである LOCAL SKILL DIR とは別物)経由で実行し、断片コマンドの個別打鍵で検証を省略しない
既に同名の branch がある場合 :秒単位スラッグで通常は衝突しないが、万一の場合はユーザーに確認
sandbox 環境での実行
このスキルはネットワーク越しの GitHub 操作(fork・ git push ・PR 作成)を必須とする。該当コマンドはコマンド単位で sandbox 無効にして実行する。ネットワーク遮断を解除できない環境では実行できない。
検証
PR 作成後、以下で完了を確認する。
PR URL が返されること
PR のタイトル・差分が意図した内容であること
sync skills lock 実行案内が出力されていること
既存スキルとの関係
Step 4 のセキュリティチェック、Step 7 の Conventional Commits、Step 8 の PR body は create pr/SKILL.md の流儀を踏襲
マージ後は sync skills lock で skills lock.json の computedHash を更新