
Contribute Skill
- 202 installs
- 1 repo stars
- Updated August 2, 2026
- fandhe-ai/agent-cli-skills
Helps with ai & agent building tasks.
About
contribute-skill is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- contribute-skill
- AI & Agent Building
- AI-coding skill
Contribute Skill by the numbers
- 202 all-time installs (skills.sh)
- Ranked #2,878 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/fandhe-ai/agent-cli-skills --skill contribute-skillAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 202 |
|---|---|
| repo stars | ★ 1 |
| Last updated | August 2, 2026 |
| Repository | fandhe-ai/agent-cli-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
contribute-skill
ローカルで改修した skills/<skill-name>/ を、skills-lock.json に記録された upstream リポジトリへ PR として投稿します。
前提条件
ghCLI がインストールされ認証済みであること(対象 org への push / PR 権限が必要)- 対象スキルが
skills-lock.jsonに登録されていること - 対象スキルのローカル改修が最新のコミットに含まれ、作業ツリーが clean であること
責務の分離
- create-pr: 現在のリポジトリ内でカレントブランチから base へ PR を作成する
- contribute-skill: 別リポジトリ(upstream)へ clone → 変更反映 → push → PR 作成を行う
外部リポジトリ貢献は clone / path 変換 / 異なる認証境界が関わるため、別スキルとして分離しています。
フロー
Step 1: 引数を検証する
SKILL_NAME="$ARGUMENTS"
# 空判定ガード: パス解決の前に SKILL_NAME を確定させる
if [[ -z "${SKILL_NAME}" ]]; then
echo "対象スキルを指定してください。候補:"
ls -1 skills/ 2>/dev/null
ls -1 .agents/skills/ 2>/dev/null
echo "(lockfile 由来のスキルは .agents/skills/ のみに存在する場合がある)"
exit 1 # ユーザーが選んだスキル名を引数に付けて再実行する
fi
# kebab-case 検証(パストラバーサル防止): パス解決より前に実施する
if [[ ! "${SKILL_NAME}" =~ ^[a-z][a-z0-9-]+$ ]]; then
echo "エラー: SKILL_NAME は小文字 kebab-case のみ許可されています: ${SKILL_NAME}"
exit 1
fi
# override: 環境変数 LOCAL_SKILL_DIR が設定済みならそれを検証して使う
if [[ -n "${LOCAL_SKILL_DIR:-}" ]]; then
if [[ "${LOCAL_SKILL_DIR}" != "skills/${SKILL_NAME}" && "${LOCAL_SKILL_DIR}" != ".agents/skills/${SKILL_NAME}" ]]; then
echo "エラー: LOCAL_SKILL_DIR は skills/${SKILL_NAME} か .agents/skills/${SKILL_NAME} のいずれかを指定してください: ${LOCAL_SKILL_DIR}"
exit 1
fi
if [[ ! -d "${LOCAL_SKILL_DIR}" ]]; then
echo "エラー: 指定された LOCAL_SKILL_DIR が存在しません: ${LOCAL_SKILL_DIR}"
exit 1
fi
else
# 自動解決(両方存在する場合は中止して override を促す)
have_skills=0; have_agents=0
[[ -d "skills/${SKILL_NAME}" ]] && have_skills=1
[[ -d ".agents/skills/${SKILL_NAME}" ]] && have_agents=1
if [[ "${have_skills}" -eq 1 && "${have_agents}" -eq 1 ]]; then
echo "エラー: skills/${SKILL_NAME} と .agents/skills/${SKILL_NAME} の両方が存在します。"
echo "環境変数 LOCAL_SKILL_DIR にどちらかを指定して再実行してください(例: LOCAL_SKILL_DIR=.agents/skills/${SKILL_NAME})。"
exit 1
elif [[ "${have_skills}" -eq 1 ]]; then
LOCAL_SKILL_DIR="skills/${SKILL_NAME}"
elif [[ "${have_agents}" -eq 1 ]]; then
LOCAL_SKILL_DIR=".agents/skills/${SKILL_NAME}"
else
echo "エラー: ローカルスキルが見つかりません: skills/${SKILL_NAME} / .agents/skills/${SKILL_NAME}"
exit 1
fi
fi引数が空の場合はパス解決に進まず、skills/ と .agents/skills/ の候補一覧を表示して終了します。Claude はその一覧をユーザーに提示し、スキル名を選んでもらってから再実行を促してください。後続の Step では ${LOCAL_SKILL_DIR}/ を使ってローカルパスを参照します。 skills/ と .agents/skills/ の両方にディレクトリが存在する場合は中止し、環境変数 LOCAL_SKILL_DIR に改修対象のパス(skills/<name> か .agents/skills/<name> のいずれか)を指定して再実行するよう案内します(silently に skills/ を優先しません)。環境変数 LOCAL_SKILL_DIR が設定済みの場合は、許可された2パスのいずれかであること・実在することを検証してから採用し、自動解決をスキップします。どちらにも存在しなければエラーで中止します。
Step 2: upstream を特定する
ルートの skills-lock.json を読み、skills.<SKILL_NAME>.source を取り出します。
# jq が使えるなら jq で取得する
SOURCE=$(jq -r ".skills[\"${SKILL_NAME}\"].source" skills-lock.json)
SOURCE_TYPE=$(jq -r ".skills[\"${SKILL_NAME}\"].sourceType" skills-lock.json)
# 安全弁: Fandhe-AI org 以外への push を拒否する
# 短縮形 (Fandhe-AI/<repo>) と URL 形式 (https://github.com/Fandhe-AI/<repo>) の両方を許可する
case "${SOURCE}" in
Fandhe-AI/*)
# 短縮形: そのまま使用
REPO_SLUG="${SOURCE}"
;;
https://github.com/Fandhe-AI/*)
# URL 形式: OWNER/REPO 形式に正規化し末尾 .git を除去する
REPO_SLUG="${SOURCE#https://github.com/}"
REPO_SLUG="${REPO_SLUG%.git}"
;;
*)
echo "エラー: source '${SOURCE}' は Fandhe-AI org のリポジトリではありません。中止します。"
exit 1
;;
esac
# sourceType が github 以外なら中止(GitHub 以外の source は本スキルの想定外)
if [[ "${SOURCE_TYPE}" != "github" ]]; then
echo "エラー: sourceType '${SOURCE_TYPE}' は github ではありません。中止します。"
exit 1
fisourceがFandhe-AI/(短縮形)またはhttps://github.com/Fandhe-AI/(URL 形式)のいずれでも始まらない場合は エラーで中止 します(安全弁:見知らぬリポジトリへ意図せず push しないため)。sourceTypeがgithub以外の場合も エラーで中止 します(GitHub 以外の source は本スキルの想定外であり、gh repo clone/gh pr createが正常動作しないため)。- 正規化後の
REPO_SLUGは以降の Step でgh repo clone・gh pr create --repoに利用します。
Step 3: 変更内容を確認する
git log --oneline -- "${LOCAL_SKILL_DIR}/"
git diff HEAD~1 HEAD -- "${LOCAL_SKILL_DIR}/"ユーザーに「この改修内容で upstream に PR を作ってよいか」を確認します。
Step 4: セキュリティチェック(必須)
create-pr と同様に以下をレビューします。
- 認証・認可の実装漏れ
- API キー・シークレットのハードコーディング
- XSS の可能性(ドキュメントでも外部埋め込みが含まれる場合)
- 入力バリデーションの欠如
- OWASP Top 10
問題があれば upstream 貢献を中止し、ユーザーに警告します。
Step 5: 作業用ディレクトリを用意する
UID_VAL=$(id -u)
TS=$(date +%Y%m%d-%H%M%S)
WORKDIR="/tmp/claude-${UID_VAL}/contribute-${SKILL_NAME}-${TS}"
mkdir -p "$WORKDIR"$TMPDIR が設定されていればそちらを優先します(サンドボックス互換)。
Step 6: upstream を clone する
# cd する前にローカルリポジトリのルートを捕捉する(cd - は stdout を汚染するため使用しない)
ORIG_DIR="$(pwd)"
gh repo clone "${REPO_SLUG}" "$WORKDIR/upstream"
cd "$WORKDIR/upstream"デフォルトブランチを取得して DEFAULT_BRANCH に設定します。
DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||')
echo "デフォルトブランチ: ${DEFAULT_BRANCH:-main}"Step 7: 変更を反映する
upstream 側でスキルがどのパス構造に置かれているか確認します。UPSTREAM_SKILL_PATH の決定は、クローンしたリポジトリのレイアウトのみで判定します(cd "$WORKDIR/upstream" 済みの前提)。
skills-lock.json の skillPath はローカル install パスであり upstream リポジトリ内の配置ではないため、使用しません。
# upstream のスキル配置はクローンしたリポジトリのレイアウトで判定する
# (skills-lock.json の skillPath はローカル install パスであり upstream の配置ではないため使わない)
if [[ -d "skills/${SKILL_NAME}" ]]; then
UPSTREAM_SKILL_PATH="skills/${SKILL_NAME}"
elif [[ -d ".agents/skills/${SKILL_NAME}" ]]; then
UPSTREAM_SKILL_PATH=".agents/skills/${SKILL_NAME}"
elif [[ -d "skills" ]]; then
# upstream が skills/ 配下で公開している慣習
UPSTREAM_SKILL_PATH="skills/${SKILL_NAME}"
mkdir -p "${WORKDIR}/upstream/${UPSTREAM_SKILL_PATH}"
elif [[ -d ".agents/skills" ]]; then
# upstream が .agents/skills/ 配下で公開している慣習
UPSTREAM_SKILL_PATH=".agents/skills/${SKILL_NAME}"
mkdir -p "${WORKDIR}/upstream/${UPSTREAM_SKILL_PATH}"
else
echo "警告: upstream にスキルルートが見つかりません。skills/ を既定として新規追加します。"
UPSTREAM_SKILL_PATH="skills/${SKILL_NAME}"
mkdir -p "${WORKDIR}/upstream/${UPSTREAM_SKILL_PATH}"
fiUPSTREAM_SKILL_PATH が確定したらコピーを実行します。
# LOCAL_SKILL_DIR は Step 1 で解決済み(skills/<name>/ または .agents/skills/<name>/)
# ORIG_DIR は Step 6 で cd する前に捕捉済み(cd - は stdout 汚染のため使用しない)
cp -R "${ORIG_DIR}/${LOCAL_SKILL_DIR}/." "${WORKDIR}/upstream/${UPSTREAM_SKILL_PATH}/"Step 8: 差分を確認する
cd "$WORKDIR/upstream"
git status
git diffユーザーに差分を見せ、内容が意図通りか確認します。
Step 9: ブランチ作成・コミット
SLUG=$(date +%Y%m%d-%H%M%S)
git switch -c "contribute/<SKILL_NAME>-${SLUG}"
git add <変更パス>
git commit -m "$(cat <<'EOF'
<type>(<scope>): <subject>
ローカルの skills/<SKILL_NAME>/ からの貢献。
EOF
)"- Conventional Commits 形式
--no-verifyは使用しない(pre-commit フックを通す)- co-author は付けない(ローカル規約に合わせる)
Step 10: push と PR 作成
git push -u origin "contribute/<SKILL_NAME>-${SLUG}"
gh pr create \
--repo "${REPO_SLUG}" \
--base "${DEFAULT_BRANCH:-main}" \
--title "<type>(<scope>): <subject>" \
--body "$(cat <<'EOF'
## Summary
- <SKILL_NAME> の改修内容(箇条書き)
## Source
ローカルの [ideas リポジトリ](../../) 側で改修後、`/contribute-skill <SKILL_NAME>` により投稿。
## Test plan
- [ ] SKILL.md を実際に Claude Code で実行
- [ ] Conventional Commits に沿ったメッセージ生成を確認
- [ ] エッジケース確認
EOF
)"--repo には Step 2 で正規化した ${REPO_SLUG}(OWNER/REPO 形式)を渡します。URL 形式から OWNER/REPO への変換は Step 2 の case 文で完了しています。
Draft PR を作成する場合は --draft を付けます(デフォルトはユーザー確認の上で決定)。
Step 11: 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/` の両方が存在する場合は中止:silently に
skills/を優先せず、環境変数LOCAL_SKILL_DIRに改修対象パスを指定して再実行を求める。LOCAL_SKILL_DIRはskills/<name>か.agents/skills/<name>の2パスのみ受理し、任意パス指定によるパストラバーサルを防ぐ - source が Fandhe-AI org 以外の場合は中止:
Fandhe-AI/(短縮形)とhttps://github.com/Fandhe-AI/(URL 形式)のみを許可し、それ以外は意図しない外部リポジトリへの push を防ぐため中止する - セキュリティ問題が見つかった場合は中止:修正後に再実行
- upstream の配置はクローンしたリポジトリのレイアウトで判定する:
skills-lock.jsonのskillPathはローカル install パス(例:.agents/skills/github-docs/SKILL.md)であり、upstream リポジトリ内の配置ではない。skillPathの dirname をUPSTREAM_SKILL_PATHに採用してはならない。判定順はskills/<name>の存在 →.agents/skills/<name>の存在 → スキルルート親ディレクトリ(skills/or.agents/skills/)の慣習 → 最終デフォルトskills/(より一般的な公開レイアウト) - 既に同名の branch がある場合:秒単位スラッグで通常は衝突しないが、万一の場合はユーザーに確認
sandbox 環境での実行
このスキルは sandbox 環境では実行できない。ネットワークアクセス・ファイルシステムへの書き込みが必要なため、通常の Claude Code セッションで実行すること。
検証
PR 作成後、以下で完了を確認する。
# PR が作成されたことを確認
gh pr view --repo "${REPO_SLUG}" --web
# または URL を直接確認(Step 11 で出力済み)- PR URL が返されること
- PR のタイトル・差分が意図した内容であること
sync-skills-lock実行案内が出力されていること
既存スキルとの関係
- Step 4 のセキュリティチェック、Step 9 の Conventional Commits、Step 10 の PR body は
create-pr/SKILL.mdの流儀を踏襲 - マージ後は
sync-skills-lockでskills-lock.jsonのcomputedHashを更新
#!/usr/bin/env bash
# skills-contribute.sh — ローカルスキルを upstream リポジトリへ PR として投稿する実例
#
# 使い方(リポジトリルートから実行):
# skills/contribute-skill/script/skills-contribute.sh <skill-name> <upstream-repo>
# (インストール先からは .agents/skills/contribute-skill/script/skills-contribute.sh)
# 例: skills/contribute-skill/script/skills-contribute.sh create-commit Fandhe-AI/agent-cli-skills
#
# このスクリプトは contribute-skill スキルが使用するコマンド集。
# Claude がフロー全体を制御するため、直接実行時は各ステップを確認しながら進めること。
# リポジトリルートから実行すること。
set -euo pipefail
SKILL_NAME="${1:-}"
UPSTREAM_REPO="${2:-}"
if [[ -z "$SKILL_NAME" || -z "$UPSTREAM_REPO" ]]; then
echo "使い方: $0 <skill-name> <upstream-repo>"
echo "例: $0 create-commit Fandhe-AI/agent-cli-skills"
exit 1
fi
# SKILL_NAME のバリデーション(kebab-case のみ許可、パストラバーサル防止)
if [[ ! "$SKILL_NAME" =~ ^[a-z][a-z0-9-]+$ ]]; then
echo "エラー: SKILL_NAME は小文字 kebab-case のみ許可されています: ${SKILL_NAME}"
exit 1
fi
# source の安全弁: Fandhe-AI/ または https://github.com/Fandhe-AI/ のみ許可
case "$UPSTREAM_REPO" in
Fandhe-AI/*)
;;
https://github.com/Fandhe-AI/*)
;;
*)
echo "エラー: 想定外の upstream: $UPSTREAM_REPO — Fandhe-AI/ 以外への push は許可されていません"
exit 1
;;
esac
# skills-lock.json に source があれば argv の UPSTREAM_REPO と照合する(誤リポ clone 防止)
if command -v jq >/dev/null 2>&1 && [[ -f skills-lock.json ]]; then
LOCK_SOURCE=$(jq -r ".skills[\"${SKILL_NAME}\"].source // empty" skills-lock.json 2>/dev/null)
if [[ -n "${LOCK_SOURCE}" ]]; then
norm_lock="${LOCK_SOURCE#https://github.com/}"; norm_lock="${norm_lock%.git}"
norm_arg="${UPSTREAM_REPO#https://github.com/}"; norm_arg="${norm_arg%.git}"
if [[ "${norm_lock}" != "${norm_arg}" ]]; then
echo "エラー: 指定された upstream (${UPSTREAM_REPO}) が skills-lock.json の source (${LOCK_SOURCE}) と一致しません。中止します。" >&2
exit 1
fi
# sourceType の安全弁: github 以外(欠落・null 含む)は gh repo clone / gh pr create が
# 成立しないため中止する(contribute-skill/SKILL.md Step 2 と同じガード)。
# lockfile にエントリが存在する場合のみ検査し、未登録の新規スキル貢献は対象外とする
LOCK_SOURCE_TYPE=$(jq -r ".skills[\"${SKILL_NAME}\"].sourceType // empty" skills-lock.json 2>/dev/null)
if [[ "${LOCK_SOURCE_TYPE}" != "github" ]]; then
echo "エラー: sourceType '${LOCK_SOURCE_TYPE}' は github ではありません。中止します。" >&2
exit 1
fi
fi
fi
# ローカルスキルのパス確認(override: 環境変数 LOCAL_SKILL_DIR が設定済みならそれを検証して使う)
if [[ -n "${LOCAL_SKILL_DIR:-}" ]]; then
if [[ "${LOCAL_SKILL_DIR}" != "skills/${SKILL_NAME}" && "${LOCAL_SKILL_DIR}" != ".agents/skills/${SKILL_NAME}" ]]; then
echo "エラー: LOCAL_SKILL_DIR は skills/${SKILL_NAME} か .agents/skills/${SKILL_NAME} のいずれかを指定してください: ${LOCAL_SKILL_DIR}"
exit 1
fi
if [[ ! -d "${LOCAL_SKILL_DIR}" ]]; then
echo "エラー: 指定された LOCAL_SKILL_DIR が存在しません: ${LOCAL_SKILL_DIR}"
exit 1
fi
else
# 自動解決(両方存在する場合は中止して override を促す)
have_skills=0; have_agents=0
[[ -d "skills/${SKILL_NAME}" ]] && have_skills=1
[[ -d ".agents/skills/${SKILL_NAME}" ]] && have_agents=1
if [[ "${have_skills}" -eq 1 && "${have_agents}" -eq 1 ]]; then
echo "エラー: skills/${SKILL_NAME} と .agents/skills/${SKILL_NAME} の両方が存在します。"
echo "環境変数 LOCAL_SKILL_DIR にどちらかを指定して再実行してください(例: LOCAL_SKILL_DIR=.agents/skills/${SKILL_NAME} $0 ${SKILL_NAME} ${UPSTREAM_REPO})。"
exit 1
elif [[ "${have_skills}" -eq 1 ]]; then
LOCAL_SKILL_DIR="skills/${SKILL_NAME}"
elif [[ "${have_agents}" -eq 1 ]]; then
LOCAL_SKILL_DIR=".agents/skills/${SKILL_NAME}"
else
echo "エラー: ローカルスキルが見つかりません: skills/${SKILL_NAME} / .agents/skills/${SKILL_NAME}"
exit 1
fi
fi
echo "==> contribute-skill: ${SKILL_NAME} → ${UPSTREAM_REPO}"
echo ""
# Step 3: 変更内容を確認する
echo "--- ローカル変更履歴 ---"
git log --oneline -- "${LOCAL_SKILL_DIR}/"
echo ""
echo "--- 最新差分 ---"
git diff HEAD~1 HEAD -- "${LOCAL_SKILL_DIR}/" 2>/dev/null || git diff -- "${LOCAL_SKILL_DIR}/"
echo ""
# Step 5: 作業用ディレクトリを用意する
UID_VAL=$(id -u)
TS=$(date +%Y%m%d-%H%M%S)
WORKDIR="/tmp/claude-${UID_VAL}/contribute-${SKILL_NAME}-${TS}"
mkdir -p "$WORKDIR"
echo "==> 作業ディレクトリ: $WORKDIR"
# Step 6: upstream を clone する
# cd する前にローカルリポジトリのルートを捕捉する(cd - は stdout 汚染があるため使用しない)
ORIG_DIR="$(pwd)"
echo "==> upstream を clone 中..."
gh repo clone "${UPSTREAM_REPO}" "${WORKDIR}/upstream"
cd "${WORKDIR}/upstream"
DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||')
echo " デフォルトブランチ: ${DEFAULT_BRANCH:-main}"
# UPSTREAM_REPO を OWNER/REPO 形式へ正規化する(URL 形式の場合に gh pr create が失敗するのを防ぐ)
REPO_SLUG="${UPSTREAM_REPO#https://github.com/}"
REPO_SLUG="${REPO_SLUG%.git}"
# Step 7: upstream のスキル配置を決定する(クローンしたリポジトリのレイアウトで判定)
# skills-lock.json の skillPath はローカル install パスであり upstream の配置ではないため使わない
UPSTREAM_SKILL_PATH=""
if [[ -d "skills/${SKILL_NAME}" ]]; then
UPSTREAM_SKILL_PATH="skills/${SKILL_NAME}"
elif [[ -d ".agents/skills/${SKILL_NAME}" ]]; then
UPSTREAM_SKILL_PATH=".agents/skills/${SKILL_NAME}"
elif [[ -d "skills" ]]; then
# upstream が skills/ 配下で公開している慣習
UPSTREAM_SKILL_PATH="skills/${SKILL_NAME}"
mkdir -p "${WORKDIR}/upstream/${UPSTREAM_SKILL_PATH}"
elif [[ -d ".agents/skills" ]]; then
# upstream が .agents/skills/ 配下で公開している慣習
UPSTREAM_SKILL_PATH=".agents/skills/${SKILL_NAME}"
mkdir -p "${WORKDIR}/upstream/${UPSTREAM_SKILL_PATH}"
else
echo "警告: upstream にスキルルートが見つかりません。skills/ を既定として新規追加します。"
UPSTREAM_SKILL_PATH="skills/${SKILL_NAME}"
mkdir -p "${WORKDIR}/upstream/${UPSTREAM_SKILL_PATH}"
fi
echo "==> upstream パス: ${UPSTREAM_SKILL_PATH}"
cp -R "${ORIG_DIR}/${LOCAL_SKILL_DIR}/." "${WORKDIR}/upstream/${UPSTREAM_SKILL_PATH}/"
# Step 8: 差分を確認する
echo ""
echo "--- upstream での変更差分 ---"
git status
git diff
echo ""
# Step 9: ブランチ作成・コミット(実際の実行は Claude が行う)
SLUG=$(date +%Y%m%d-%H%M%S)
BRANCH="contribute/${SKILL_NAME}-${SLUG}"
echo "==> 次のステップ(Claude が実行します):"
echo " git switch -c '${BRANCH}'"
echo " git add ${UPSTREAM_SKILL_PATH}/"
echo " git commit -m '<type>(<scope>): <subject>'"
echo " git push -u origin '${BRANCH}'"
echo " gh pr create --repo ${REPO_SLUG} --base ${DEFAULT_BRANCH:-main} --title '<title>' --body '...'"
echo ""
echo "作業ディレクトリ: ${WORKDIR}/upstream"