بنقرة واحدة
issue-close
イシュー完了時に使用。PRマージ・worktree削除・ブランチ安全削除を一括実行
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
イシュー完了時に使用。PRマージ・worktree削除・ブランチ安全削除を一括実行
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
設計書(draft/design/)に基づき、TDD(テスト駆動開発)アプローチを用いて機能を実装する。
実装完了後の成果物に対し、設計整合性とコード品質の観点から厳格なレビューを実施する
Issue 作成後・workflow 起動前に人間が明示起動する要件 interview。one-way door を含みうる重要な Issue で、未決の decision tree を 1 問ずつ推奨案付きで確認し、決定事項と provenance を Issue に固定するときだけ使用する。軽微な Issue や workflow 実行中には自動起動しない。
Issue要件に基づき、draft/design/に設計書を作成する。worktree内での作業が前提。
Create a validated sequential Issue series plan from an explicitly ordered GitHub Issue list. Use when a maintainer wants to generate or update an ID-named YAML file under .kaji/series, select standard workflows from Issue type metadata and workflow descriptions, or preview a series without starting it.
dev workflow 向けの最終チェック。PR 前に品質ゲート、docs 整合、設計書昇格、Issue 更新をまとめて確認する。
| description | イシュー完了時に使用。PRマージ・worktree削除・ブランチ安全削除を一括実行 |
| name | issue-close |
イシュー対応完了後のクリーンアップを実行します。 PR マージ、worktree 削除、ブランチ削除、Issue クローズを一括実行します。
| タイミング | このスキルを使用 |
|---|---|
| PRがApproveされマージ可能 | ✅ 使用 |
| PRレビュー待ち | ❌ 待機 |
| 作業途中 | ❌ 不要 |
ワークフロー内の位置: implement → review-code → i-dev-final-check → i-pr → close
常に注入される変数:
| 変数 | 型 | 説明 |
|---|---|---|
issue_id | str | 正規化済み Issue ID(GitHub 数値または local ID) |
issue_ref | str | 人間可読の Issue 参照(GitHub では #<issue_id>、local では bare ID) |
step_id | str | 現在のステップ ID |
provider 解決時に追加で注入される変数:
| 変数 | 型 | 説明 |
|---|---|---|
provider_type | str | github / local のいずれか。本 Skill の経路分岐に使用 |
default_branch | str | ベースブランチ名(main 等)。local 経路で merge / push の引数に使用 |
branch_name | str | フィーチャーブランチ名(feat/<id> 等) |
worktree_dir | str | worktree 絶対パス |
$ARGUMENTS = <issue_id>
コンテキスト変数 issue_id が存在すればそちらを使用。
なければ $ARGUMENTS の第1引数を issue_id として使用。
issue_ref はハーネス経由ではプロンプトに自動注入される(prompt.py 側で provider 別に整形)。手動実行時は issue_id から導出する: GitHub 数値 ID なら #<issue_id>、local-* 形式なら bare ID(# を付けない)。
/i-pr でPRが作成済みであること[provider_type] に応じて手順が分岐する。
[provider_type] が github(または未注入の legacy 環境)→ 既存の
Step 1〜6 を順に実行する(uv run kaji pr merge / worktree 削除 / branch 削除 /
git pull / uv run kaji issue close / 報告)。[provider_type] が local → 後述の provider=local の場合 セクションへ
ジャンプし、design.md § local mode における /issue-close の手順 (6 step) を
実行する。github 用の Step 1〜6 は実行しない(PR 概念が無いため)。親 Issue を close する直前に、provider に関係なく本手順を実行する。
正本は
docs/dev/workflow_completion_criteria.md
§ follow-up Issue への移管、本文 template は
templates/follow-up-issue.md とする。
親本文の ## 完了条件 内にある末尾サブセクション
### ワークフロー完了後の確認項目 だけを対象にし、次の ## 見出しまたは本文末尾までから
- [ ] の項目を抽出する。
| 状態 | 処理 |
|---|---|
| セクションなし | follow-up なしで close 手順を続行 |
- なし、または未チェック項目 0 件 | follow-up なしで close 手順を続行 |
| 未チェック項目 1 件以上 | 以降の検索・作成・マーカー追記を実行 |
| 見出し重複、チェックリストとして解釈不能 | 項目喪失を避けるため ABORT |
i-dev-final-check / i-doc-final-check が同サブセクションを更新対象外としているため、
ここに残る [ ] は未完了のまま follow-up へ移す。[x] は移さない。
follow-up のタイトルは次の完全一致形式に固定する。
[follow-up] [parent_title] ([issue_ref])
まず親本文に次のマーカーがあるか確認する。
<!-- kaji-follow-up-issue: [follow_up_issue_id] -->
FOLLOW_UP_ID に設定して uv run kaji issue view で確認し、
次の 3 点をすべて満たすときだけ再利用する
state が open である<!-- kaji-follow-up-parent: [issue_ref] --> が 1 件あるABORTABORT。未チェック項目が親に残っているのに
追跡先が閉じている状態であり、close 済み follow-up を再利用すると追跡が失われる。
同名タイトルの open Issue 検索へフォールバックしてもマーカーとの不整合が残るため、
自動復旧はしない。人間が (a) 完了済みの項目を親本文で [x] に更新する、
(b) follow-up Issue を reopen する、(c) 親のマーカー行を削除して再作成させる、
のいずれかを選んだうえで再実行するFOLLOW_UP_STATE=$(uv run kaji issue view "$FOLLOW_UP_ID" --json state -q '.state')
# GitHub は OPEN/CLOSED、local は open/closed を返すため小文字化して比較する
case "$(printf '%s' "$FOLLOW_UP_STATE" | tr '[:upper:]' '[:lower:]')" in
open) : ;;
*)
echo "ABORT: marked follow-up Issue $FOLLOW_UP_ID is not open (state=$FOLLOW_UP_STATE)"
exit 1
;;
esac
PARENT_TITLE=$(uv run kaji issue view [issue_id] --json title -q '.title')
FOLLOW_UP_TITLE="[follow-up] $PARENT_TITLE ([issue_ref])"
uv run kaji issue list --state open --limit 1000 --json number,title > /tmp/kaji-open-issues.json
jq -r --arg title "$FOLLOW_UP_TITLE" \
'.[] | select(.title == $title) | .number' \
/tmp/kaji-open-issues.json > /tmp/kaji-follow-up-candidates.txt
| 完全一致件数 | 処理 |
|---|---|
| 0 | 新規作成 |
| 1 | 候補の .number を FOLLOW_UP_ID に設定し、既存 open Issue を再利用 |
| 2 以上 | 対象を一意に決められないため ABORT |
作成後にマーカー追記だけが失敗した場合も、再実行時は完全一致検索で作成済み Issue を 再利用する。これにより重複起票を防ぐ。
完全一致候補がない場合だけ、templates/follow-up-issue.md を読み、以下を実値へ置換して
/tmp/kaji-follow-up-body.md を作る。
[parent_issue_ref] / [parent_issue_title][unchecked_items]: 抽出した未チェック項目だけ[reference_docs]: 親本文の docs/... 参照。なければ正本
docs/dev/workflow_completion_criteria.mdCREATE_OUTPUT=$(uv run kaji issue create \
--title "$FOLLOW_UP_TITLE" \
--body-file /tmp/kaji-follow-up-body.md) || {
echo "ABORT: follow-up Issue creation failed"
exit 1
}
FOLLOW_UP_ID=${CREATE_OUTPUT##*/}
# local provider では create した issue.md を atomic commit する。
# github provider では --commit が除去されるため同じコマンドを使える。
uv run kaji issue edit "$FOLLOW_UP_ID" --commit \
--body-file /tmp/kaji-follow-up-body.md || {
echo "ABORT: follow-up Issue persistence failed"
exit 1
}
親本文に有効なマーカーがなかった場合だけ、新規作成・既存検索で得た Issue ID の マーカーを親本文末尾へ 1 件追記する。Step 2 で有効なマーカーを確認済みの場合は追記を スキップし、既存の 1 件を維持する。
CURRENT_BODY=$(uv run kaji issue view [issue_id] --json body -q '.body')
{
printf '%s\n\n' "$CURRENT_BODY"
printf '<!-- kaji-follow-up-issue: %s -->\n' "$FOLLOW_UP_ID"
} > /tmp/kaji-parent-body-with-follow-up.md
uv run kaji issue edit [issue_id] --commit \
--body-file /tmp/kaji-parent-body-with-follow-up.md || {
echo "ABORT: parent follow-up marker update failed; parent Issue remains open"
exit 1
}
追記後、uv run kaji issue view で同じマーカーが 1 件だけ存在することを確認する。作成・再利用、
マーカー追記、追記後確認のいずれかが失敗した場合は ABORT とし、親 Issue の close を
実行しない。
結果を記録:
follow_up_result= 「対象なし」/「作成: [follow_up_issue_id]」/ 「既存再利用: [follow_up_issue_id]」。完了報告に含める。
Issue本文からWorktree情報を取得します:
uv run kaji issue view [issue_id] --json body -q '.body'
以下の情報を抽出:
> **Worktree**: \../kaji-[prefix]-[issue_id]`` → worktree パス> **Branch**: \[prefix]/[issue_id]`` → ブランチ名git worktree list の最初の行が常に main worktree(bare repository のルート)を示す:
MAIN_REPO=$(git worktree list | head -1 | awk '{print $1}')
注意:
git rev-parse --show-toplevelは現在の worktree のルートを返すため、 worktree 内から実行すると main repo を取得できない。必ずgit worktree listを使うこと。
worktree 内にいる場合は main repo に移動:
cd "$MAIN_REPO"
uv run kaji pr merge [branch_name]
マージコミットを作成してブランチ履歴を保持する。ブランチ削除は worktree 削除後に Step 4.5 で行う。
結果を記録:
pr_merge_result= 「マージ済み」。この値は Step 6 で使用する。
git worktree remove "$MAIN_REPO/../kaji-[prefix]-[issue_id]"
$MAIN_REPOは Step 2 で取得済み。
結果を記録:
worktree_result= 「削除済み」。この値は Step 6 で使用する。
worktree 削除後にローカル・リモートブランチを削除する。
git fetch [git_remote] で [git_remote]/[default_branch] を最新化してから、merge-base --is-ancestor でマージ済み判定を行い、安全に削除する。
ローカル削除とリモート削除は独立して実行し、片方の失敗がもう片方をブロックしない。
ブランチが既に存在しない場合はスキップする。
# 1. fetch して [git_remote]/[default_branch] を更新
git fetch [git_remote]
# 2. ローカルブランチ削除: 存在確認 → マージ済み判定 → 安全な -D
if git show-ref --verify --quiet refs/heads/[branch_name]; then
if git merge-base --is-ancestor [branch_name] [git_remote]/[default_branch]; then
git branch -D [branch_name]
else
echo "WARNING: branch not merged into [git_remote]/[default_branch], skipping local delete"
fi
fi
# 3. リモートブランチ削除(ローカル削除の成否に依存しない)
git ls-remote --exit-code --heads [git_remote] [branch_name] >/dev/null 2>&1
LS_EXIT=$?
if [ "$LS_EXIT" -eq 0 ]; then
if ! git push [git_remote] --delete [branch_name]; then
echo "ERROR: git push [git_remote] --delete failed"
exit 1
fi
elif [ "$LS_EXIT" -eq 2 ]; then
echo "INFO: remote branch already deleted"
else
echo "ERROR: git ls-remote failed (exit $LS_EXIT)"
exit 1
fi
# 4. stale remote-tracking ref を掃除
git fetch --prune [git_remote]
結果を記録:
local_branch_result= 「削除済み」/「未存在を確認」/「未マージのためスキップ」remote_branch_result= 「削除済み」/「未存在を確認」/「削除失敗(要手動対応)」これらの値は Step 6 で使用する。
git pull [git_remote] [default_branch]
結果を記録:
pull_result= 「最新化済み」。この値は Step 6 で使用する。
「共通: ワークフロー完了後の確認項目の移管」を実行する。失敗時は ABORT とし、
Step 5.5 へ進まない。
uv run kaji issue close [issue_id] --reason completed
結果を記録:
close_result= 「クローズ済み」/「クローズ失敗(要手動対応)」。この値は Step 6 で使用する。重要:
uv run kaji issue closeが失敗した場合は verdict を ABORT にすること。Issue が未クローズのまま残ることは許容しない。
Step 3〜5.5 の結果を使って、stdout への報告と Issue タイムラインへのコメント投稿の両方を行う。
各ステップで記録した結果変数を使い、コメント内容を動的に組み立てて投稿する:
uv run kaji issue comment [issue_id] --commit --body-file - <<'COMMENT_EOF'
## Issue クローズ完了
| 項目 | 状態 |
|------|------|
| PR | [pr_merge_result] |
| worktree | [worktree_result] |
| ローカルブランチ | [local_branch_result] |
| リモートブランチ | [remote_branch_result] |
| main | [pull_result] |
| follow-up Issue | [follow_up_result] |
| Issue | [close_result] |
COMMENT_EOF
[pr_merge_result]等のプレースホルダーは、実際の実行結果に置き換えること。ハードコードしない。
以下の形式で報告してください:
## Issue クローズ完了
| 項目 | 状態 |
|------|------|
| Issue | [issue_ref] |
| PR | [pr_merge_result] |
| worktree | [worktree_result] |
| ローカルブランチ | [local_branch_result] |
| リモートブランチ | [remote_branch_result] |
| main | [pull_result] |
| follow-up Issue | [follow_up_result] |
| Issue 状態 | [close_result] |
[provider_type] が local のとき、PR 概念が無いため
design.md § local mode における /issue-close の手順 (6 step) を実行する。
重要 (worktree 運用): bare repository + worktree パターンでは
[default_branch]は feature worktree とは別の worktree(通常 main repo 側) で checkout されている。そのため merge / close commit は base worktree 側 で実行し、feature worktree ([worktree_dir]) はその後で削除する。 feature worktree 内でgit switch [default_branch]を実行しても、別 worktree がそのブランチを保持しているため Git に拒否される。
cd [worktree_dir]
test -z "$(git status --porcelain)" || { echo "ABORT: uncommitted changes in [worktree_dir]"; exit 1; }
git rev-parse --abbrev-ref HEAD | grep -qE "^[a-z]+/local-[a-z0-9]+-[0-9]+(-[a-z0-9-]+)?$" || { echo "ABORT: not on feature branch"; exit 1; }
未コミット変更 / feature ブランチ外なら ABORT。
git worktree list --porcelain から [default_branch] を checkout している
worktree を抽出する。見つからなければ user が手動で base 側を準備する必要が
あるため ABORT。
# [default_branch] を checkout している worktree を取得
BASE_WT=$(git worktree list --porcelain | awk -v b="[default_branch]" '
/^worktree / { wt=$2 }
$0 == "branch refs/heads/" b { print wt; exit }
')
test -n "$BASE_WT" || { echo "ABORT: no worktree has [default_branch] checked out. Run 'git worktree add <path> [default_branch]' or 'git switch [default_branch]' in your main checkout first."; exit 1; }
cd "$BASE_WT"
# Step 2.1: 3 段ガードによる救済 commit 判定(Issue local-p1-16 B)
#
# 標準動線(各 skill での `uv run kaji issue {comment,edit} --commit`)が機能していれば
# base worktree は clean。蓄積が残っている場合は LocalProvider 永続化由来の path
# のみ救済し、それ以外は ABORT する。
#
# 救済対象 (LocalProvider 命名規則):
# - .kaji/issues/<issue_id>-<slug>/issue.md
# - .kaji/issues/<issue_id>-<slug>/comments/<4桁seq>-<machine_id>.md
# 命名規則は installed kaji package の LocalProvider 契約に従う。
DIRTY=$(git status --porcelain)
if [ -n "$DIRTY" ]; then
# 条件 1: dirty path がすべて [issue_id] の永続化 whitelist に一致するか検査
ISSUE_DIR_RE='^\.kaji/issues/[issue_id]-[a-z0-9-]+/(issue\.md|comments/[0-9]{4}-[a-z0-9]{1,16}\.md)$'
UNRELATED=$(printf '%s\n' "$DIRTY" | awk -v re="$ISSUE_DIR_RE" '
{
# rename / copy ("R old -> new") は救済対象外として ABORT に倒す
if (match($0, /->/)) { print; next }
# 先頭 3 文字 (status + space) を除いた残りを path として扱う
path = substr($0, 4)
# quoted path (path に空白等あり) は対応外として ABORT
if (substr(path, 1, 1) == "\"") { print; next }
if (path !~ re) { print }
}
')
if [ -n "$UNRELATED" ]; then
echo "ABORT: dirty files outside LocalProvider persistence whitelist in base worktree $BASE_WT:"
printf '%s\n' "$UNRELATED"
echo " Allowed pattern: $ISSUE_DIR_RE"
exit 1
fi
# 条件 2: whitelist 命名規則の glob で限定 add + atomic commit
# - `comments/` ディレクトリ全体を add してはならない (note.txt 等を巻き込む)
# - `git commit --only` で他の staged change を HEAD に混入させない
git add \
".kaji/issues/[issue_id]-"*"/issue.md" \
".kaji/issues/[issue_id]-"*"/comments/"[0-9][0-9][0-9][0-9]-*.md \
2>/dev/null || true
git commit --only \
-m "chore(local): salvage uncommitted issue files for [issue_ref]" \
-- \
".kaji/issues/[issue_id]-"*"/issue.md" \
".kaji/issues/[issue_id]-"*"/comments/"[0-9][0-9][0-9][0-9]-*.md \
|| { echo "ABORT: salvage commit failed"; exit 1; }
# 条件 3: 救済後の残差を再検証 (rename/copy/rm 等の取りこぼしを検出)
test -z "$(git status --porcelain)" || {
echo "ABORT: residual dirty files after salvage commit in base worktree $BASE_WT:"
git status --porcelain
exit 1
}
fi
# remote 設定がある場合のみ fetch + ff-only merge。
# fetch 失敗 (network 断 / 認証エラー / suspended account 等) は WARNING で skip し、
# local-only で close を完結させる (Step 6 の push も同様に warning で続行する設計と整合)。
# `uv run kaji run` 非対話モードでは AskUserQuestion 経由のリカバリ不可のため、
# deterministic に local fallback すること。手動 push は remote 復旧後に実施。
if git remote get-url [git_remote] >/dev/null 2>&1; then
if git fetch [git_remote] [default_branch] 2>&1; then
git merge --ff-only "[git_remote]/[default_branch]" || { echo "ABORT: ff-only merge failed in base worktree"; exit 1; }
else
echo "WARNING: git fetch [git_remote] [default_branch] failed; proceeding with local-only close (manual push needed after remote recovery)"
fi
fi
ABORT 条件:
WARNING 継続条件:
git fetch 失敗 (remote 到達不可 / 認証失敗) → local merge は実行、push は Step 6 で warning skip標準動線で各 skill が uv run kaji issue {comment,edit} --commit を使っていれば、ここまで到達した時点で
base worktree は clean のはず。救済 commit は標準動線が機能しなかった場合の安全装置として残す。
git merge --no-ff --no-edit [branch_name] || { echo "ABORT: merge conflict, resolve manually in $BASE_WT then retry"; exit 1; }
衝突したら ABORT。Issue は open のまま、user が手動 resolve した後で再実行する。
最初に「共通: ワークフロー完了後の確認項目の移管」を実行する。follow-up 作成または
親マーカー追記に失敗した場合は ABORT とし、親 Issue を close しない。
移管成功後、親 Issue を close する。
uv run kaji issue close [issue_id] --reason completed
git add .kaji/issues/[issue_id]-*/issue.md
git commit -m "chore(issue): close [issue_ref]" || { echo "ABORT: commit failed"; exit 1; }
--reason completed は明示で書く(LocalProvider.close_issue の default も
completed だが、Skill markdown 上で明示することで読み手の予期外を減らす)。
Step 4 完了で Issue close は確定。以降の失敗は警告のみ。
base worktree に居る状態で feature worktree を削除する。cwd == 削除対象 を
回避するため、Step 2 の cd "$BASE_WT" は維持したまま実行する。
git worktree remove [worktree_dir] || echo "WARNING: worktree remove failed for [worktree_dir]; manual cleanup needed"
git branch -d [branch_name] || echo "WARNING: branch delete failed for [branch_name]; manual cleanup needed"
if git remote get-url [git_remote] >/dev/null 2>&1; then
git push [git_remote] [default_branch] || echo "WARNING: push failed; manual push needed"
fi
実行完了後、以下の形式で verdict を出力すること:
---VERDICT---
status: PASS
reason: |
クローズ完了
evidence: |
事後確認の移管要否を確認し、必要な follow-up Issue の作成または再利用と親マーカー追記を完了した。PR マージ・worktree 削除・main 最新化・Issue クローズ済み
suggestion: |
---END_VERDICT---
重要: verdict は stdout にそのまま出力 すること。Issue コメントや Issue 本文更新とは別に、最終的な verdict ブロックは stdout に残す。
| status | 条件 |
|---|---|
| PASS | クローズ完了 |
| ABORT | follow-up 作成・再利用・親マーカー追記の失敗(マーカー参照先が close 済みの場合を含む)、またはクローズ失敗(uv run kaji issue close 失敗を含む / local merge 衝突) |