Help us improve
Share bugs, ideas, or general feedback.
From claude-issueops
capture mode (--capture): Decision を抽出・確認・投稿し、セッション継続。 close mode (default): capture フロー + summary 投稿 + cross-issue scope の memory 昇格。
npx claudepluginhub etoyama/claude-issueops --plugin claude-issueopsHow this skill is triggered — by the user, by Claude, or both
Slash command
/claude-issueops:session-closerThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
claude-issueops プラグインの **書き戻し側メインエントリ** スキル。Claude Code セッション中に下された Decision を Issue コメントに persistent memory として書き戻し、close モードでは要約と cross-issue scope の memory 昇格まで実行する。
Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
Explores codebases via GitNexus: discover repos, query execution flows, trace processes, inspect symbol callers/callees, and review architecture.
Share bugs, ideas, or general feedback.
claude-issueops プラグインの 書き戻し側メインエントリ スキル。Claude Code セッション中に下された Decision を Issue コメントに persistent memory として書き戻し、close モードでは要約と cross-issue scope の memory 昇格まで実行する。
--capture: capture モード。Decision を抽出・確認・投稿してセッションへ制御を戻す。要約投稿と memory 昇格はスキップ。3 層構造で実装される:
AskUserQuestion でのユーザー対話、subcommand のオーケストレーション。bin/session_closer.py): stdin/stdout JSON で skill とやりとりする Python 唯一のエントリポイント。subcommand を dispatch するだけで業務ロジックは持たない。src/issueops/): 副作用を持たない関数群 (session_closer, transcript_reader, decision_extractor, dedup_checker, issue_resolver, state_writer, pending_decisions, gh_adapters, memory_escalate 等)。重要: AskUserQuestion は 必ずこの SKILL.md (Claude Code セッション内) から呼ぶ。Python 側からは呼ばない。Python は対話結果 (UserDecision[] 等) を入力 JSON として受け取り、結果を出力 JSON として返すだけの純粋関数として設計されている。
{
"schema_version": 1,
"subcommand": "<subcommand 名>",
"session_id": "<sid>",
"project_dir": "/abs/path",
// subcommand 固有のフィールド
}
// 成功時
{
"schema_version": 1,
"ok": true,
"result": { /* subcommand 固有 */ },
"warnings": ["..."]
}
// 失敗時
{
"schema_version": 1,
"ok": false,
"error": {
"kind": "transcript-missing" | "issue-resolution" | "gh-failure" | "extractor-parse" | "internal",
"message": "...",
"gh_failure_kind": "auth" | "network" | "rate-limit" | "unknown",
"hint": "gh auth status を実行してください"
}
}
schema_version の不一致を検出したら、即座にエラーで止めること。バージョン違いの bin と通信し続けない。
すべて bin/session_closer.py に対し echo '<JSON>' | uv run python bin/session_closer.py で叩く。
read-transcripttranscript ファイルを offset 以降のバイト範囲で読み出す。
// in
{
"schema_version": 1,
"subcommand": "read-transcript",
"session_id": "abc123",
"project_dir": "/repo",
"transcript_path": "/repo/.claude/projects/abc123/transcript.jsonl",
"offset": 0
}
// out
{
"schema_version": 1,
"ok": true,
"result": { "content": "...", "end_offset": 12345 }
}
resolve-issue対象 Issue 番号を Tier 1 (status:in-progress ラベル) → branch hint 交差 → Tier 2 (branch pattern) の順で解決。曖昧なら ambiguous_candidates を返すので、SKILL.md 側で AskUserQuestion (single) を呼んで再投入する。
// in
{
"schema_version": 1,
"subcommand": "resolve-issue",
"session_id": "abc123",
"project_dir": "/repo",
"branch": "feat/8-session-closer-skill"
}
// out (確定)
{ "schema_version": 1, "ok": true, "result": { "issue_number": 8, "tier": "tier1" } }
// out (曖昧)
{ "schema_version": 1, "ok": true, "result": { "ambiguous_candidates": [7, 8, 12] } }
filter-dedupTier 1 (ローカル captured_slugs) と Tier 2 (Issue 既存コメントの marker scan) で候補を除外。Tier 2 の gh 失敗時は tier2_skipped_kind (gh 失敗種別の文字列) を返し abort しない。成功時は tier2_skipped_kind 自体が出力に含まれない。
// in
{
"schema_version": 1,
"subcommand": "filter-dedup",
"session_id": "abc123",
"project_dir": "/repo",
"issue_number": 8,
"candidates": [ /* Candidate[] */ ],
"captured_slugs": ["already-posted-slug"]
}
// out (Tier 2 成功)
{
"schema_version": 1,
"ok": true,
"result": { "candidates": [ /* ... */ ] }
}
// out (Tier 2 が gh 失敗で skip — Tier 1 のみで継続)
{
"schema_version": 1,
"ok": true,
"result": { "candidates": [ /* ... */ ], "tier2_skipped_kind": "auth" }
}
post-decisionsUserDecision[] を gh issue comment で投稿。state は触らない (commit-state と分離)。部分失敗を許容し posted[] (成功 slug) と failed[] (失敗エントリ) を返す。gh 失敗が 1 件でも発生していれば、最後の失敗種別を top-level gh_failure_kind (および利用可能なら gh_hint) として併記する。
// in
{
"schema_version": 1,
"subcommand": "post-decisions",
"session_id": "abc123",
"project_dir": "/repo",
"issue_number": 8,
"decisions": [
{ "candidate": { /* ... */ }, "final_scope": "issue" }
]
}
// out (全成功)
{
"schema_version": 1,
"ok": true,
"result": {
"posted": ["use-bin-adapter"],
"failed": []
}
}
// out (部分失敗)
{
"schema_version": 1,
"ok": true,
"result": {
"posted": ["use-bin-adapter"],
"failed": [
{ "slug": "isolate-gh", "error": "gh: authentication required", "kind": "auth", "hint": "gh auth status を実行してください" }
],
"gh_failure_kind": "auth",
"gh_hint": "gh auth status を実行してください"
}
}
failed[] の各エントリは slug (必須) と error (失敗メッセージ、必須) を持つ。gh コマンド失敗由来なら kind (auth / network / rate-limit / unknown) と任意で hint も乗る。bin 内部例外なら kind/hint は省略され error のみ。
commit-statestate file の merge update を atomic write で実行する 唯一のチャネル。patch の中身は SKILL.md がユーザー選択を反映して組み立てる (State Writes Table 参照)。
// in
{
"schema_version": 1,
"subcommand": "commit-state",
"session_id": "abc123",
"project_dir": "/repo",
"patch": {
"skill_ran_at": "2026-04-26T05:30:00Z",
"last_processed_offset": 12345,
"captured_slugs": ["use-bin-adapter"]
}
}
// out
{ "schema_version": 1, "ok": true, "result": { "state_path": "/repo/session-state/abc123.json" } }
summaryclose モードでのみ呼ぶ。<!-- claude-issueops:session-closer:summary:<session_id> --> marker の既存検査 → 未投稿なら summary コメントを投稿。idempotent。
本文構造 (#64): marker + ## Session summary ヘッダの後、captured_slugs_total が 1 件以上あれば ### Captured decisions (N) セクションを追記し、各 slug を箇条書きで列挙する。空文字 / 非文字列の entry は drop。captured_slugs_total が空 or 未指定なら marker + ヘッダのみ。SKILL.md 側で完全に body を制御したい場合は body: string を入力に渡せば auto-render を上書きできる (escape hatch)。
// in
{
"schema_version": 1,
"subcommand": "summary",
"session_id": "abc123",
"project_dir": "/repo",
"issue_number": 8,
"captured_slugs_total": ["use-bin-adapter", "isolate-gh"]
}
// out (投稿成功)
{ "schema_version": 1, "ok": true, "result": { "posted": true, "marker": "<!-- claude-issueops:session-closer:summary:abc123 -->", "comment_url": "https://github.com/owner/repo/issues/8#issuecomment-..." } }
// out (idempotent skip: 同 session の summary が既出)
{ "schema_version": 1, "ok": true, "result": { "posted": false, "skipped": "idempotent", "marker": "<!-- claude-issueops:session-closer:summary:abc123 -->" } }
// out (gh view 失敗で重複検査不能 — SKILL.md 側で warnings に変換)
{ "schema_version": 1, "ok": true, "result": { "posted": false, "skipped": "view-failed", "gh_failure_kind": "auth" } }
// out (gh post 失敗 — marker は試行済み)
{ "schema_version": 1, "ok": true, "result": { "posted": false, "skipped": "post-failed", "marker": "<!-- claude-issueops:session-closer:summary:abc123 -->", "gh_failure_kind": "auth", "gh_hint": "gh auth status を実行してください" } }
escalatefinal_scope == "cross-issue" の Decision のみを Claude memory ディレクトリに昇格。memory_escalate.write_memory_file + update_memory_index を呼ぶ。
// in
{
"schema_version": 1,
"subcommand": "escalate",
"session_id": "abc123",
"project_dir": "/repo",
"decisions": [ /* PostedDecision[] with final_scope=cross-issue */ ],
"project_memory_dir": "/Users/u/.claude/projects/abc/memory"
}
// out (全成功)
{ "schema_version": 1, "ok": true, "result": { "written": ["use-bin-adapter"] } }
// out (一部 slug の memory write / index 更新が失敗 — best-effort、コメントはロールバックしない)
{ "schema_version": 1, "ok": true, "result": { "written": ["use-bin-adapter"], "warnings": ["memory write failed for slug isolate-gh: <reason>"] } }
written[] は memory file と index 更新の 両方 に成功した slug のみ含む。途中で失敗した slug は warnings[] に理由を残し、後段の処理を継続する (R-8.4 best-effort)。
save-pendinggh 失敗で「ローカルに保存」を選んだ未投稿 Decision を <sid>.pending-decisions.json に追記。schema_version=1 を含む。
// in
{
"schema_version": 1,
"subcommand": "save-pending",
"session_id": "abc123",
"project_dir": "/repo",
"issue_number": 8,
"decisions": [ /* UserDecision[] (未投稿分) */ ]
}
// out
{ "schema_version": 1, "ok": true, "result": { "pending_path": "/repo/session-state/abc123.pending-decisions.json" } }
以下を SKILL.md (= 本セッション内の Claude) が忠実に順番通りに実行する。各ステップで返ってきた ok: false は即座にユーザーに状況を伝え、必要に応じて中断する。
引数 --capture の有無を確認する。あれば capture モード、なければ close モード。
state file から last_processed_offset (既定 0) を読み、read-transcript を呼ぶ。返ってきた content を LLM プロンプトに食わせて Decision 候補 (Candidate[]) を JSON で抽出する。slug は kebab-case、4 フィールド (what / why / alternatives / consequences) すべて非空、scope_hint は "issue" か "cross-issue" のどちらかで初期推定。JSON parse 失敗は extractor-parse エラーで abort。
resolve-issue を呼ぶ。
issue_number が返ってきたらそれを使う。ambiguous_candidates: [7, 8, 12] が返ってきたら AskUserQuestion (single select) で「どの Issue に投稿しますか?」とユーザーに選ばせる。選択結果を branch_pattern か --issue-number-override 相当の追加フィールドで再投入。commit-state で skill_ran_at のみ patch する (Issue 解決失敗で skill が起動した事実は残す)。filter-dedup に candidates と captured_slugs を渡す。
candidates が空 → 「新しい決定は検出されませんでした」とユーザーに通知して終了。commit-state で skill_ran_at のみ patch。tier2_skipped_kind が present (gh 失敗、値は auth / network / rate-limit / unknown のいずれか) → 警告だけ表示し Tier 1 のみで続行。AskUserQuestion (multiSelect: true) で各候補を提示する。ラベルは slug + what の冒頭 80 文字に切り詰めた 1 行サマリ。同時に各候補に対し scope の二択 (issue / cross-issue) を表示し、LLM 推定値を初期選択にする。承認 + scope 確定後、UserDecision[] ({candidate, final_scope}) を構築する。
全候補が却下されたら「ユーザーが全候補を却下しました」と表示して終了し、commit-state で skill_ran_at のみ patch。
post-decisions を呼ぶ。返ってきた posted[] と failed[] を保持する。この時点では state は変わっていない (post-decisions は state に触らない)。
failed が空でなければ AskUserQuestion (single select) で [ローカルに保存して後で再投稿, 破棄, 中断] の 3 択を提示する。
save-pending を呼んで未投稿 Decision を <sid>.pending-decisions.json に追記。captured_slugs には成功分のみ追加。ユーザー選択に応じた patch を State Writes Table から組み立て、commit-state を呼ぶ。
| シナリオ | skill_ran_at | last_processed_offset | captured_slugs |
|---|---|---|---|
| 全成功 | now | end_offset | append (成功 slug) |
| 部分失敗 → 保存 | now | end_offset | append (成功分) |
| 部分失敗 → 破棄 | now | end_offset | append (成功分) |
| 部分失敗 → 中断 | now | (更新しない) | append (成功分) |
| 全候補却下 | now | (更新しない) | -- |
| 候補 0 件で early exit | now | end_offset | -- |
| Issue 解決失敗 | now | -- | -- |
| transcript 不在 | -- | -- | -- |
close モードの場合のみ、capture 累計が 1 件以上あるなら以下を実行:
summary を呼ぶ。<!-- claude-issueops:session-closer:summary:<session_id> --> marker は session_id 込みで idempotent。既出なら自動 skip。final_scope == "cross-issue" の Decision を集めて escalate を呼ぶ。memory ファイル書き込み失敗は警告のみで Issue コメントはロールバックしない。最終出力は次の形式:
Posted N decisions, escalated M to memory, skipped K duplicates.
エラーで abort した場合は理由 + 復旧示唆を 1 画面に収まる長さで出す。長い診断は ${CLAUDE_PROJECT_DIR}/session-state/<session_id>.skill.log に書き出す。
error.kind | 意味 | SKILL.md の動作 |
|---|---|---|
transcript-missing | transcript ファイルが見つからない | 状況を表示して abort、state は触らない |
issue-resolution | 全 tier で Issue 番号確定不能 | commit-state で skill_ran_at のみ patch、ユーザー誘導表示 |
gh-failure | gh コマンド失敗。gh_failure_kind 4 種に分類済 | post-decisions 内なら 3 択フォールバック、それ以外は警告で続行 (Tier 2 dedup) |
extractor-parse | LLM 抽出 JSON 不正 | 「再 invoke してください」を表示、state は触らない |
internal | bin 内部例外 | スタックトレース要約 + log path を表示、state は触らない |
gh_failure_kind == "auth" の場合、必ず hint を併記してユーザーに表示する (gh auth status を実行してください 等)。
--capture は Tier 1 + Tier 2 dedup により「すべて投稿済み」と判定し clean に終了する。commit-state 前に中断された場合、state file は atomic write のため前回値を保持する。再 invoke で安全。commit-state は state 更新の唯一のチャネル。post 後に対話を挟む構造のため、post-decisions と commit-state を分離している。CLAUDE_ISSUEOPS_VERIFICATION_FIXTURE=verification-fixtures/<v-id>.json と CLAUDE_ISSUEOPS_VERIFICATION_MODE=1 の 両方 を設定したセッションでは、AskUserQuestion 応答を fixture から読み込んで bypass する。Claude が L3 verification を一気通貫で自動実行するためのもの。本番運用では絶対に有効化しない。