
Update Issue Tree
- 134 installs
- 1 repo stars
- Updated August 2, 2026
- fandhe-ai/agent-cli-skills
Helps with ai & agent building tasks.
About
update-issue-tree is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- update-issue-tree
- AI & Agent Building
- AI-coding skill
Update Issue Tree by the numbers
- 134 all-time installs (skills.sh)
- Ranked #3,615 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 update-issue-treeAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 134 |
|---|---|
| repo stars | ★ 1 |
| Last updated | August 2, 2026 |
| Repository | fandhe-ai/agent-cli-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
update-issue-tree
既存の Issue ツリーを棚卸しし、ルート issue 本文を最新状態に再生成する。 closed 親下に残置された open issue の付け替え・孤児の再配置・phase ラベルの同期を実施し、implement-issue-tree が post-order DFS で消化できる構造を維持する。
使い方
ルートのトラッキング issue 番号を引数として渡す。
update-issue-tree 42前提条件
ghCLI がインストールされ、認証済みであること(gh auth statusで確認)- 対象リポジトリへの Issue 書き込み権限があること
フロー
Step 1: ツリー全体を再帰取得する
ルート issue から sub_issues API を再帰的に呼び出し、全階層のツリー構造を取得する。 ページネーションを考慮し、per_page=100 で全件取得する。
ROOT_NUMBER="<ルート issue 番号>"
# ルート直下の sub-issues を取得(ページネーション対応)
fetch_sub_issues() {
local PARENT="${1}"
local PAGE=1
while true; do
RESULT=$(gh api \
"repos/{owner}/{repo}/issues/${PARENT}/sub_issues?per_page=100&page=${PAGE}")
echo "${RESULT}"
COUNT=$(echo "${RESULT}" | jq 'length')
if [ "${COUNT}" -lt 100 ]; then break; fi
PAGE=$((PAGE + 1))
done
}
# ルートから再帰的にツリーを構築
fetch_sub_issues "${ROOT_NUMBER}"各 issue の state(open / closed)・ラベル・タイトルを記録してツリーマップを作成する。
Step 2: 棚卸し対象を特定する
取得したツリーマップを分析し、以下のケースを特定する。
| ケース | 対応方針 |
|---|---|
| closed 親の下に open issue が残置されている | 適切な open Phase 親へ付け替え |
| どの親にも紐付いていない孤児 issue がある | 該当 Phase 親へ紐付け(Phase が不明な場合はユーザーに確認) |
| phase ラベルが親と一致しない issue がある | ラベルを同期 |
| 既存 Phase に収まらない新規タスクがある | 新 Phase 親の新設を検討 |
| 4h 超の issue が分解されていない | sub-issue に分解(create-issue-tree と同じ粒度基準) |
棚卸し対象の一覧をユーザーに提示し、方針確認を取ってから変更を実行する。
Step 3: closed 親下の残置 open issue を付け替える
closed 親の下に残置されている open issue を、対応する open Phase 親へ移動する。
# sub_issue_id は issue 番号ではなく database id を渡す(GitHub sub-issues API 仕様)
ISSUE_ID=$(gh api "repos/{owner}/{repo}/issues/${ISSUE_NUMBER}" --jq '.id')
# 既存の親から外す(sub_issues API の DELETE)
gh api \
--method DELETE \
"repos/{owner}/{repo}/issues/${OLD_PARENT}/sub_issues" \
-F "sub_issue_id=${ISSUE_ID}"
# 新しい親へ紐付ける
gh api \
--method POST \
"repos/{owner}/{repo}/issues/${NEW_PARENT}/sub_issues" \
-F "sub_issue_id=${ISSUE_ID}"Step 4: 孤児 issue を再配置する
どの親にも紐付いていない孤児 issue を適切な Phase 親へ紐付ける。 Phase が不明な issue はタイトル・本文を読んで判断し、判断できない場合はユーザーに確認する。
# sub_issue_id は database id を渡す(issue 番号ではない)
ORPHAN_ID=$(gh api "repos/{owner}/{repo}/issues/${ORPHAN_NUMBER}" --jq '.id')
gh api \
--method POST \
"repos/{owner}/{repo}/issues/${PHASE_NUMBER}/sub_issues" \
-F "sub_issue_id=${ORPHAN_ID}"Step 5: 必要に応じて新 Phase 親を新設する
既存 Phase に収まらない新規タスクが多い場合、新 Phase 親 issue を作成してルートへ紐付ける。
# phase ラベルが存在しないリポジトリでは issue 作成が失敗するため、必ず事前作成する
# (作成済みの場合は失敗を無視して続行する)
gh label create "phase:N" --color "0075ca" 2>/dev/null || true
# gh issue create は URL を出力する(--json 非対応)。URL 末尾から番号を抽出する
NEW_PHASE_URL=$(gh issue create \
--title "feat(phase-N): Phase N タイトル" \
--label "phase:N" \
--body "$(cat <<'EOF'
## 概要
Phase N の実装タスクをまとめる親 issue。
## タスク一覧
| Issue | タイトル | 分解 |
|-------|---------|------|
EOF
)")
NEW_PHASE_NUMBER=$(printf '%s' "${NEW_PHASE_URL}" | grep -oE '[0-9]+$')
# ルートへ紐付け。sub_issue_id は issue 番号ではなく database id を渡す(GitHub sub-issues API 仕様)
NEW_PHASE_ID=$(gh api "repos/{owner}/{repo}/issues/${NEW_PHASE_NUMBER}" --jq '.id')
gh api \
--method POST \
"repos/{owner}/{repo}/issues/${ROOT_NUMBER}/sub_issues" \
-F "sub_issue_id=${NEW_PHASE_ID}"Step 6: phase ラベルを同期する
各 issue の phase ラベルが親 Phase と一致しているか確認し、不一致のラベルを修正する。
# ラベルを追加
gh issue edit "${ISSUE_NUMBER}" --add-label "phase:1"
# 古いラベルを削除
gh issue edit "${ISSUE_NUMBER}" --remove-label "phase:0"Step 7: 4h 超の issue を sub-issue に分解する
棚卸し中に 4h 超と判断した issue は、create-issue-tree と同じ粒度基準で sub-issue に分解する。
# phase ラベルが存在しない場合に備えて事前作成する(作成済みなら no-op)
gh label create "phase:N" --color "0075ca" 2>/dev/null || true
# sub-issue を作成(URL 末尾から番号を抽出)
SUB_URL=$(gh issue create \
--title "feat: サブタスク名" \
--label "phase:N" \
--body "...")
SUB_NUMBER=$(printf '%s' "${SUB_URL}" | grep -oE '[0-9]+$')
# 親 issue へ紐付け(sub_issue_id は database id)
SUB_ID=$(gh api "repos/{owner}/{repo}/issues/${SUB_NUMBER}" --jq '.id')
gh api \
--method POST \
"repos/{owner}/{repo}/issues/${ISSUE_NUMBER}/sub_issues" \
-F "sub_issue_id=${SUB_ID}"Step 8: ルート issue 本文を再生成して更新する
棚卸し後の最新ツリー状態を反映したルート issue 本文を生成し、gh issue edit で更新する。
gh issue edit "${ROOT_NUMBER}" --body "$(cat <<'EOF'
## 概要
全 open issue を Phase 別に 1 ツリーへ整理。各 Phase 親 issue を sub-issues として紐付け。
## 棚卸しで実施した整理(YYYY-MM-DD)
- closed 親下の残置 issue の付け替え: N 件
- 孤児の再配置: N 件
- phase ラベル同期: N 件
- 新 Phase 親の新設: N 件
## Phase 別実装計画
| Phase | 親 issue | 直下 | 総 open 件数 |
|-------|----------|------|-------------|
| Phase 1 | #<phase1_number> タイトル | N | N |
| Phase 2 | #<phase2_number> タイトル | N | N |
### Phase 1: タイトル
| Issue | タイトル | 分解 |
|-------|---------|------|
| #N | タイトル | - |
| #N | タイトル | sub-issue あり |
## 運用
- 新規 issue は起票時に Phase 親へ紐付ける
- 実行順は sub-issues リスト順が正
- closed 親の下に open issue を残置しない
- implement-issue-tree が post-order DFS で消化可能な構造を維持する
EOF
)"Step 9: 棚卸し結果を報告する
## update-issue-tree 完了レポート
### 対象ルート issue
- #N: タイトル
### 棚卸し実施内容
| 操作 | 件数 |
|------|------|
| closed 親下の残置 issue 付け替え | N 件 |
| 孤児 issue の再配置 | N 件 |
| phase ラベル同期 | N 件 |
| 新 Phase 親の新設 | N 件 |
| 4h 超 issue の sub-issue 分解 | N 件 |
### 現在の Phase 別サマリー
| Phase | 親 issue | open 件数 |
|-------|----------|----------|
| Phase 1 | #N | N 件 |
### 要確認事項(自動配置できなかった issue)
- #N: タイトル — 確認理由検証
- ルート issue 本文の Phase 別表が更新されていることを確認する
- closed Phase 親の下に open issue が残置されていないことを確認する
# 全 sub-issues の state を確認
gh api "repos/{owner}/{repo}/issues/${ROOT_NUMBER}/sub_issues" \
--jq '.[] | {number: .number, state: .state, title: .title}'
# Phase 親の sub-issues も確認
gh api "repos/{owner}/{repo}/issues/${PHASE_NUMBER}/sub_issues" \
--jq '.[] | {number: .number, state: .state}'
# phase ラベルの同期確認(各 Phase 親直下で確認)
gh api "repos/{owner}/{repo}/issues/${PHASE_NUMBER}/sub_issues" \
--jq '.[] | {number: .number, labels: [.labels[].name]}'注意事項
- 棚卸し前に変更内容をユーザーに提示して確認を取る(Step 2 参照)
- ページネーション: sub-issues が 100 件を超える場合は
per_page=100&page=Nでページングして全件取得する - シェルコマンドの変数は必ず
"${var}"でクォートする(コマンドインジェクション対策) --no-verifyは絶対に使用しない- `gh issue create` は `--json` 非対応。issue URL を stdout に出力するため、
| grep -oE '[0-9]+$'で末尾の番号を抽出する - sub_issues API(POST / DELETE)の `sub_issue_id` は issue 番号ではなく database id(GitHub 仕様)。
gh api "repos/{owner}/{repo}/issues/<number>" --jq '.id'で id を取得してから渡す。番号をそのまま渡すと誤った issue を操作する/404 になる - 孤児 issue の Phase が判断できない場合は推測せずにユーザーへ確認する
- sub_issues の DELETE API で付け替えを行う際、操作対象の issue 番号を必ず確認してから実行する
- ツリー更新後は implement-issue-tree が post-order DFS で正しく消化できる構造になっているか確認する