Skip to content
Back to skills

Issueops Cleanup

ASecurity

Use after an IssueOps cycle merged, or for "이슈옵스 정리", "워크트리 지우고 브랜치 지우고 이슈 닫아줘": closes the linked issue and removes the worktree and local branch. Unmerged: issueops-abandon.

  • 6 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
ai-agentsgit

Works with

  • terminal
  • cli
  • mcp

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned November 7, 2026

npx -y skills add m16khb-org/issueops --skill issueops-cleanup --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Issueops Cleanup?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Issueops Cleanup
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/m16khb-org-issueops-cleanup/badge)](https://www.skillsdirectory.com/skills/m16khb-org-issueops-cleanup)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: issueops-cleanup
description: 'Use after an IssueOps cycle merged, or for "이슈옵스 정리", "워크트리 지우고 브랜치 지우고 이슈 닫아줘": closes the linked issue and removes the worktree and local branch. Unmerged: issueops-abandon.'
---

# IssueOps Cleanup

Finish one record-backed, merged IssueOps cycle through harness-owned surfaces.

Exactly three effects are authorized after target confirmation: close and verify
the linked parent issue, remove the recorded local worktree, delete its local branch.
Remote branch deletion is a separate decision and `cleanup remote-branch` flow.

This body is the complete actor contract for copied or body-only use. Installed
`issueops`, `issueops-remote-write`, `git-operations`, and `gitlab-usecase` can supply
additional recipes; their absence never requires installation or evaluator material.
Resolve optional links from this file's real, symlink-resolved location, not cwd.
Use only observed CLI contracts; report missing inputs/tools rather than inventing them.

## Entry and authority

Resolve the exact ID as below, then run `issueops next --id "$ISSUEOPS_ID" --json`.
Require `stage.key=done`; otherwise follow the named stage/`next_command`, not cleanup.
Before each durable mutation, re-read the record and `execution whoami --json`.
Use its `record_actor_flags` for records and `claim_actor_flags` for execution
operations where the CLI requires them; never assemble identity flags yourself.
Preserve the exact ID, recorded generation, native actor, source cwd and target
worktree. A released completion is not permission to reclaim or bypass a holder.
`issueops status` and `issueops feedback add` are supported aliases; authenticated
recording belongs to this stage. `quality inspect` is not a semantic skill runner;
`issueops skill-bench` is unsupported.

## Preconditions

1. Prefer the supplied ID/`$ISSUEOPS_ID`; otherwise `issueops list --repo "$PWD" --json`.
   Ask which ID only if zero or multiple plausible cycles remain.
2. Run from the record's source repository, never the worktree being removed. A session
   started inside the worktree (for example the Herdr space opened for implementation) is a
   requester occupant even after `cd`; run cleanup from a session opened in the source repository.
3. Require `done`, a released execution lease, and provider-verified merged PR/MR.
   `execution complete` owns done/release; this skill never records completion.
4. Linked child tasks must already have verified close evidence.
5. Dirty worktree, branch mismatch, unreadable provider state
   or pending external intent blocks cleanup. Occupants do NOT block: preview
   lists `workspace_processes` (pid, command, start time, descendant/collateral
   counts); typed apply stops them. An omitted `workspace_processes` means none.
   Requester occupancy still blocks: `requester_occupies_worktree` includes
   ancestors. `worktree_is_source_checkout` also
   blocks. Use a different terminal/worktree, never manual process killing.
6. The remote source branch must be absent, or the user must have chosen to
   leave it. On `remote_branch_absent`, present both exits and let the user pick:
   - delete through the separately authorized `issueops cleanup remote-branch` flow, then finish;
   - finish with `--keep-remote-branch`. Record deletion prevents later typed
     deletion through this record. Report `kept_remote_branch` and the audit
     fragment `remote_branch_kept=<branch>@<oid>`. The issue-number branch name
     and provider link keep it discoverable; finish does not write the issue body.
   A remote that cannot be read blocks the same way and takes the same two
   exits; `--keep-remote-branch` records `state: "unreadable"` instead of an OID.
7. Prepared and provider-observed merged base must match. On `base_branch_drifted`,
   `retargeted_base` or `merged_base_remote_unobserved`, read [base drift](references/base-drift.md).

Unmerged retirement (draft PR/MR, issue and remote branch closure) belongs to
`issueops-abandon`/typed `cleanup abandon`, not this path. An unmerged PR/MR the
developer approved is merged first by `issueops-merge`: `issueops remote merge-pr`
merges without deleting the branch, and that skill's step 6 deletes the remote branch
through `issueops cleanup remote-branch` before handing off here.

## Project docs

Before the preview, read the `.issueops/CAUTIONS.md` index (when absent, write "파일 없음" instead of opening it) and route the task through
`project_docs_route` (or `issueops project route-docs --repo "$PWD" --task "<cleanup
summary>" --json` when MCP is unavailable) to pick the dated `cautions/` and `adr/`
records about cleanup, worktree processes, and remote branches. Recorded cleanup
failures are the first things to check in the preview. In the confirmation summary,
record each caution that applies with its path, or "none applied".

## Preview the exact targets

Read the lifecycle and cleanup inventory:

```text
issueops status --id "$ISSUEOPS_ID" --json
issueops cleanup status --id "$ISSUEOPS_ID" --merged --json
issueops remote close-issue --id "$ISSUEOPS_ID" \
  --provider "$PROVIDER" --json
```

Without `--confirm`, close is a dry-run. Verify live Git targets:

```text
git -C "$WORKTREE_PATH" status --short
git -C "$WORKTREE_PATH" symbolic-ref --quiet --short HEAD
git -C "$WORKTREE_PATH" rev-parse --verify HEAD
git -C "$REPO_ROOT" rev-parse --verify "refs/heads/$BRANCH"
```

Require a clean status, a symbolic branch exactly equal to `$BRANCH`, and a
worktree HEAD OID exactly equal to the local branch OID. If the provider exposes
the merged artifact head OID, require it to equal the local branch OID too.
A detached, repurposed, mismatched, or advanced worktree blocks cleanup.

Before confirmation, status `missing` may contain only `completion_reflected`
and `issue_closed`. Its other gates (`pr_phase`, `remote_artifact_*`,
`child_tasks_closed`, `worktree_*`, `branch_match`, `remote_branch_*`) must pass.
Finish preview renders the same two completion gates and their `next_command`;
after reflection only `issue_closed` remains. Do not wait for an empty list
before steps 1-2; only afterward must both previews be clear.
The close-issue dry-run must report `ok: true`. Any other missing gate or provider
error blocks closure: report it and stop before writing.

A parent with delegated child cycles closes their provider tasks first:
`issueops cleanup close-children --id "$ISSUEOPS_ID" --merged` (preview, then `--confirm`)
satisfies `child_tasks_closed`; remote-branch cleanup comes after it. Each child
cycle then runs this skill on its own ID: remote-branch, reflect-completion,
close-issue (already closed is success), finish.

From these results, state:

- lifecycle ID and issue URL;
- provider and verified merged PR/MR;
- exact local worktree path;
- exact local branch, worktree HEAD OID, local branch OID and available merged-head match;
- that the remote branch will not be deleted;
- every process the apply will stop (`workspace_processes`
  with pid/command/start time and descendant/collateral counts),
  because unsaved work in those processes is lost;
- every readiness blocker.

Missing/ambiguous targets or other blockers mean stop. Never infer targets from an issue title.

## Confirmation boundary

Obtain one explicit confirmation naming all three destructive/external effects:

```text
이슈 <URL>을 닫고, HEAD <WORKTREE_HEAD_OID>인 로컬 워크트리 <PATH>와
OID <BRANCH_OID>인 로컬 브랜치 <BRANCH>를 삭제할까요?
apply가 먼저 종료하는 것: 프로세스 <N>개(<pid:command …>).
원격 브랜치는 삭제하지 않습니다(merge 단계에서 이미 지웠으면 "원격 브랜치는 merge 단계에서 삭제했습니다").
주의사항: <Project docs에서 고른 caution마다 "문서 경로: 해당 문장 인용", 없으면 "열어 본 caution <경로 목록>, 해당 없음">
```

If no processes are listed, say nothing will be stopped. The `주의사항:` line is the
record the `Project docs` section asks for; write it in the confirmation itself.

The latest user message must confirm these exact targets; generic "cleanup" authorizes preview only.

Exception: when the original request explicitly authorized cleanup of **this cycle** in its approval
sentence (e.g. "merge하고 정리까지 끝내줘 ... 정리는 승인함") and no later user message narrowed or
stopped it, that approval stands in for the confirmation only if all of these hold: the preview's
worktree, branch, and issue are the record's; the worktree HEAD and local branch OID equal the
merged head; the worktree has no uncommitted or untracked changes; and `workspace_processes`
lists nothing to stop (descendant and collateral counts zero). The finish preview observes
processes even while `completion_reflected` or `issue_closed` is still missing (exit 1), so read
it there before those writes; an absent `workspace_processes` field there means none. Such an approval also covers the
issue close and completion reflection writes, which still run as preview then the same confirm.
Print the confirmation text above (with the `주의사항:` line) as the record even when not asking.
If anything differs or cannot be determined, show the targets and ask again.

## Apply in fail-closed order

### 1. Reflect completion into the issue

Preserve the team's progress report before closing; otherwise finish blocks on
`completion_reflected` (`issueops list` shows the same gap as `completion_unreflected: true`).
Every remote write uses preview → identical confirm →
readback. Changed body means a new preview; uncertain results mean reconcile,
never repeat a create/write or bypass the harness with raw provider mutations.

- Read the merged PR body and `issueops status --id "$ISSUEOPS_ID" --json`.
- Write one or two result sentences, then three to six flow lines (plan, what the
  review changed, implementation with the PR link, what was checked, what is
  left). Call `fluent-korean` if installed; otherwise directly review complete
  Korean sentences, clear subjects, concrete results and unnecessary modifiers.
  Remove secrets. Fix readability warnings or record why each remains.
- Save a temporary file outside the worktree; the issue body is the enduring record.

```text
issueops remote reflect-completion --id "$ISSUEOPS_ID" \
  --provider "$PROVIDER" --body-file "$RESULT_FILE" --json
issueops remote reflect-completion --id "$ISSUEOPS_ID" \
  --provider "$PROVIDER" --body-file "$RESULT_FILE" --confirm --json
```

Require no `readability` critical finding: full SHA, local path or over 2,000 characters is refused.

Require confirmed `ok: true` and matching body/URL readback; already-reflected is idempotent success.

### 2. Close and verify the issue

```text
issueops remote close-issue --id "$ISSUEOPS_ID" \
  --provider "$PROVIDER" --confirm --json
```

Require `ok: true`, `closed: true`, verified closed state; already-closed is idempotent success.

### 3. Re-preview local cleanup

Closure changes readiness: obtain a fresh fingerprint.

```text
issueops cleanup finish --id "$ISSUEOPS_ID" \
  --provider "$PROVIDER" --preview --json
```

Carry the user's `--keep-remote-branch` choice into this preview; it reports
`kept_remote_branch` and includes the flag in `next_command`. Without it, a
remaining remote branch blocks on `remote_branch_absent` and yields no fingerprint.

If `worktree_present=true`, repeat all four live Git checks after closure and before apply.

If a prior typed apply removed the worktree but retained the record (`worktree_present=false`):

- do not run `git -C "$WORKTREE_PATH"` commands;
- require evidence of the worktree removal: the prior apply result, or, when that
  apply was killed without output, the record's `cleanup_attempt` (operation
  `finish`) together with this preview's `worktree_present=false`;
- require `git worktree list --porcelain` not to contain `$WORKTREE_PATH`;
- when `branch_present` is true, re-read `refs/heads/$BRANCH` and require its
  OID to equal the OID previously confirmed by the user;
- when `branch_present` is false, require `git show-ref --verify --quiet
  "refs/heads/$BRANCH"` to exit `1`.

Require:

- `ok: true`;
- an empty `missing` list (the field is omitted when empty);
- a non-empty `fingerprint`;
- `worktree_path` and `branch` equal the targets the user confirmed;
- when the worktree remains present, its live HEAD OID and local branch OID
  equal the confirmed OIDs;
- during typed partial-failure recovery, every still-present branch OID equals
  the confirmed branch OID.

Changed path/name/OID means stop and reconfirm new targets. Never reuse a stale fingerprint.

### 4. Apply the emitted command

Execute the preview's `next_command` exactly. It must be the typed form:

```text
issueops cleanup finish --id "$ISSUEOPS_ID" \
  --apply --confirm --fingerprint "$FINGERPRINT" --json
```

The emitted command may also carry `--generated-by-executable`, `--generated-by-sha256`, and
`--generated-for-generation`. They bind it to the binary and generation that produced it; keep
them as emitted (a different binary or generation refuses it instead of running a stale command).

Never substitute raw `git worktree remove`, `git branch -d/-D`, `git update-ref`,
`git push origin --delete`, or manual terminal/process stops.
The fingerprint binds worktree, branch OID and occupant receipts.
Apply stops occupants with HUP+TERM, KILL, and re-observation, and
failure stops at `workspace_processes_stop`; it then removes
the worktree and CAS-deletes the local branch; emits audit and deletes the record.
Any destructive failure retains the record. `workspace_processes_stop` failure
means remaining occupants; re-preview rather than improvise.
Never append remote branch deletion to this flow.

## Verify the observable result

After apply:

1. Require `ok: true` and `record_deleted: true`.
2. If the worktree was present, require `worktree_removed: true`, and report
   `workspace_processes_stopped` exactly as the
   apply returned it.
3. If the local branch was present, require `branch_deleted: true`.
4. From the source repository, verify:

```text
git worktree list --porcelain
git show-ref --verify --quiet "refs/heads/$BRANCH"
```

The removed worktree path must be absent, and `show-ref` must exit `1`.
5. Re-read the remote issue with the provider and require a closed state.
6. If the worktree was removed, close its Herdr space or workspace per
   [Herdr close after cleanup](../issueops/references/session-choice-herdr.md#worktree-정리-뒤-herdr-화면-닫기).
7. Report the issue URL, removed worktree, removed local branch, remote issue
   state, the Herdr view result, and explicitly state that the remote branch was untouched.

On partial failure report `failed_step` and `next_command`; recover only through the retained
record and the worktree-aware rules above. Do not improvise or report partial work as complete.

Files in this skill

  • SKILL.md14.6 KB
  • agents/openai.yaml496 B
  • references/base-drift.md1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.