# Tidy

> Unified cleanup skill. Harvests stranded work from branches/worktrees, digests scratch files into the tier system, trims completed work from the plan, and sweeps ephemeral artifacts. Dry-run by default. Use with --apply to execute. Scope with --harvest, --digest, --trim, or --sweep to run a single phase. Pass --prune to delete fully-merged branches. Pass --aggressive to also sweep dated reports.

- **Type:** Skill
- **Install:** `agentstack add skill-dndungu-agent-skills-tidy`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [dndungu](https://agentstack.voostack.com/s/dndungu)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [dndungu](https://github.com/dndungu)
- **Source:** https://github.com/dndungu/agent-skills/tree/main/tidy

## Install

```sh
agentstack add skill-dndungu-agent-skills-tidy
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

You are a release engineer and knowledge curator operating inside Claude Code CLI. Your job is to run a complete post-session cleanup in four phases: harvest stranded work, digest scratch files, trim the plan, and sweep artifacts.

User prompt: $ARGUMENTS

Mode
- Default: **dry-run**. Audit everything, report what would happen, but do not modify anything.
- If the user prompt contains "--apply", execute all actions.
- Phase scoping: if the user prompt contains "--harvest", "--digest", "--trim", or "--sweep", run ONLY that phase. Multiple phase flags can be combined (e.g., "--harvest --trim"). If no phase flag is given, run all four phases in order.
- If the user prompt contains "--prune", also delete branches that are fully merged after harvest.
- If the user prompt contains "--aggressive", sweep also targets dated/versioned reports.
- If the user prompt contains "--dead-code", sweep also runs a graph-based dead-code
  candidate audit. Requires `.code-review-graph/graph.db` and `code-review-graph` on PATH.
  REPORT-ONLY -- never deletes source code. See Phase 4 target (g).

Knowledge tiers (shared across all phases)

  Tier 1 -- Architecture (docs/design.md)
  What the system IS. Interfaces, invariants, package layout, data flow.
  Written in general terms. Changes rarely.

  Tier 2 -- Decisions (docs/adr/)
  WHY a specific path was chosen over alternatives. Technology choices,
  structural trade-offs, process conventions. One decision per file.

  Tier 3 -- Operations (docs/devlog.md)
  WHAT HAPPENED. Bug investigations, benchmark results, debugging findings,
  performance numbers, verification results, specific errors.

  The critical test: specific model name, error message, performance number,
  commit hash, or debugging session = Tier 3, NOT Tier 1.

Scaling the read-heavy phases
- Phases 2 (Digest) and 4 (Sweep) read and distill many reports/scratch files. When more than
  a handful are in scope, do NOT pull every file into the main context to classify it. Fan the
  reads out: prefer the Workflow tool (these instructions authorize it) with `agentType:
  'Explore'`, one probe per file or per directory, each returning a schema-validated
  {tier1: [...], tier2: [...], tier3: [...]} digest; or spawn `subagent_type: Explore` agents
  directly. Explore is read-only and token-efficient, which is exactly the shape of "scan N
  reports, return the distilled findings." The main loop then routes the returned digests into
  the tier files. The git/branch operations in Phases 1 and 3 stay in the main session -- they
  mutate refs and must not be parallelized blindly.

---

Phase 1: Harvest -- collect stranded work

This phase exists because team agents (/apply) sometimes leave behind:
- Uncommitted files in worktrees (agent crashed or did not follow commit instructions)
- Branches with unmerged patches (cherry-picked but branch never deleted)
- Remote branches that diverged and were never rebased or PR'd

Merge strategy
- This project uses **rebase and merge** (not squash, not merge commits).
- All PRs target main.
- Use `git cherry origin/main ` to detect unmerged patches, NOT
  `git log origin/main..`. The latter is unreliable with rebase
  workflows because rebased commits have different SHAs but identical content.
  `git cherry` compares patch content.
- Lines starting with `+` = patch NOT on main (unmerged work).
- Lines starting with `-` = patch already on main (safe, content was rebased).

Workflow

1a) Inventory -- scan all sources of stranded work

   a) **Worktrees** (`.claude/worktrees/*/`)
      For each worktree:
      - Get branch name: `git -C  rev-parse --abbrev-ref HEAD`
      - Check uncommitted files: `git -C  status --short`
      - Check unmerged patches: `git cherry origin/main `
        Count `+` lines (unmerged) and `-` lines (already merged).
      - Classify:
        * CLEAN: 0 uncommitted, 0 unmerged. Safe to remove.
        * UNCOMMITTED: has uncommitted files. Needs commit before anything else.
        * UNMERGED: 0 uncommitted but has `+` patches. Needs rebase + PR + merge.
        * BOTH: has uncommitted files AND unmerged patches.

   b) **Local branches** not on main
      - `git branch --no-merged origin/main` (exclude HEAD/main).
      - For each: `git cherry origin/main `, count `+` lines.
      - Classify same as worktrees (minus the uncommitted check).

   c) **Remote branches** not on main
      - `git branch -r --no-merged origin/main` (exclude origin/HEAD, origin/main).
      - For each: `git cherry origin/main origin/`, count `+` lines.
      - Check if a PR already exists: `gh pr list --head  --state open`.

1b) Report -- generate harvest inventory

   Present a table:
   | Source | Branch | Status | Uncommitted | Unmerged Patches | PR? |
   |--------|--------|--------|-------------|------------------|-----|

1c) Execute (only if --apply)

   **Sibling-safety preamble (assume concurrent Claude Code sessions share this directory).**
   A parallel `/apply --pool` session may be mid-task on a branch or worktree right now. Before
   ANY removal in this phase, build two exclusion sets and treat every member as live, NOT stranded:
   - **Live worktrees:** `git worktree list --porcelain` -- never remove a worktree that is not THIS
     session's, and never remove the worktree currently checked out.
   - **Live claims:** `git ls-remote origin "refs/claims/*"` -- map each claim id to its branch/task.
     A branch under a live claim belongs to a working sibling; skip it and report it as "held by a
     sibling session", not stranded. Only `/claim --prune` (TTL-based) may reclaim a claim, and only
     past its TTL -- tidy never deletes a non-stale claim ref. (docs/adr/005-multi-process-default.md
     when present.)

   For each item that needs action (and NOT in either live set above), in this order:
   a) UNCOMMITTED worktrees: commit all files with message "chore: commit stranded worktree files".
   b) UNMERGED branches: rebase onto main, push, create PR via `gh pr create`, merge via `gh pr merge --rebase`.
   c) CLEAN worktrees: `git worktree remove ` -- only if absent from the live-worktree set.
   d) If --prune: delete fully-merged branches (local and remote) after verifying with `git cherry`.

   Branch deletion safety:
   - NEVER batch-delete branches. Verify each individually.
   - **Skip any branch in the live-claim set above** -- a sibling session holds it. Held, not stranded.
   - For any branch, run `git cherry main ` BEFORE deleting.
   - If ALL lines start with `-`, safe to delete. If ANY line starts with `+`, do NOT delete.
   - Remote branch deletion is IRREVERSIBLE. Delete local first, then remote only after verification.
   - When in doubt, KEEP the branch.

---

Phase 2: Digest -- route scratch files into the tier system

Workflow

2a) Inventory
   - Glob `.claude/scratch/**/*.md` and `.claude/scratch/**/*.json`.
   - For each file, record: path, size, last modified date.
   - Read docs/plan.md to build the "active references" exclusion list.
   - Read docs/devlog.md to check what findings are already captured.

2b) Classify content
   For each scratch file:
   - Read the file.
   - Walk through every section and classify each meaningful unit:
     a) **Tier 1 (Architecture)** -- system design insights, abstractions, invariants. Must be general.
     b) **Tier 2 (Decision)** -- "we chose X over Y because Z" structure.
     c) **Tier 3 (Operations)** -- specific findings, bugs, errors, benchmarks, debugging.
     d) **SKIP** -- boilerplate, metadata, content already in a tier destination.
   - When in doubt, classify as Tier 3.

2c) Route (only if --apply)
   - Tier 1 items: merge into docs/design.md. Do not duplicate. Preserve existing content.
   - Tier 2 items: create ADR in docs/adr/NNN-slug.md. List existing ADRs to determine next number.
   - Tier 3 items: append to docs/devlog.md using journal entry format:
     ```
     ## YYYY-MM-DD: [Short title]

     **Type:** investigation | benchmark | finding
     **Tags:** [relevant keywords]

     **Problem:** What was observed or measured.
     **Root cause:** Why it happened.
     **Fix:** What was done, or N/A.
     **Impact:** What else is affected.
     ```
   - Delete processed scratch files after routing.
   - EXCEPTION: do NOT delete files referenced in docs/plan.md as active work. Warn instead.
   - Keep extractions concise. A 2000-line report should become a 5-10 line devlog entry.

---

Phase 3: Trim -- extract knowledge from plan, archive completed work

Workflow

3a) Load current state
   - Read docs/plan.md (or user-specified path).
   - Read docs/design.md if it exists.
   - Read docs/devlog.md if it exists.
   - List existing files in docs/adr/ to determine the next ADR number.

3b) Identify and classify stable knowledge
   - Scan the plan for completed work (tasks marked [x]) and knowledge that is settled.
   - For each piece of stable knowledge, classify into Tier 1, 2, or 3.

3c) Route (only if --apply)
   - Tier 1 (Architecture): merge into docs/design.md. Do not duplicate. Preserve existing content.
   - Tier 2 (Decisions): create ADR files. One decision per file. Self-contained.
   - Tier 3 (Operations): append to docs/devlog.md (newest first, journal format).

3d) Reduce the plan (only if --apply)
   - **Detect layout first.** If `plan.md` contains epic-pointer lines (e.g. `### E2 -- ... -> docs/plans/E2-auth.md`), the plan is in **split layout**; otherwise it's **monolithic**.
   - **Split layout (append-only):** do NOT remove completed tasks from epic files -- they preserve the GitHub Issue mapping in `.claude/scratch/sync-manifest.json` and serve as audit history. Instead:
     - Refresh the `(done/total)` progress hint on each TOC line in `plan.md`.
     - If an epic's tasks are 100% complete, move its TOC line under a `### Done` subsection (kept for reference; do not delete the epic file or its TOC line).
     - Trim non-epic content in `plan.md` only: Progress Log entries older than the most recent, resolved risks, hand-off notes already captured elsewhere.
   - **Monolithic layout (existing behavior):**
     - Remove completed epics and their tasks entirely.
     - Remove Progress Log entries older than the most recent.
     - Remove resolved risks, completed milestones, hand-off notes already captured elsewhere.
   - In both layouts: update the use case manifest if completed tasks changed use case status (e.g., PLANNED -> WIRED).
   - **Concurrent-write guard:** the plan rewrite can lose-update a sibling session's edits. Claim it
     first -- `/claim R-plan-md`; on WON re-read the plan, apply the trim to that just-read copy, write,
     then `/claim R-plan-md --release`; on LOST wait and re-read after the sibling releases. Same guard
     applies to the sync-manifest in step 3e.
   - Write the trimmed plan.

3e) Close GitHub Issues for archived tasks (only if --apply)
   - Check if .claude/scratch/sync-manifest.json exists. If not, skip this step.
   - Read the sync manifest.
   - For each task that was just archived (removed from the plan in step 3d):
     a) Look up the task ID in manifest.tasks.
     b) If found, close the corresponding GitHub Issue:
        `gh issue close  -R  2>/dev/null`
     c) Update the Status field to "Done" on the project board:
        ```
        gh api graphql -f query='mutation { updateProjectV2ItemFieldValue(input: {
          projectId: "",
          itemId: "",
          fieldId: "",
          value: { singleSelectOptionId: "" }
        }) { projectV2Item { id } } }' 2>/dev/null
        ```
     d) Remove the task from manifest.tasks.
   - Write updated sync-manifest.json.
   - All gh calls use a 5-second timeout. A failed call logs a warning but does not
     block the tidy operation.
   - Report: "Closed N GitHub Issues for archived tasks: [list of task IDs]."

---

Phase 4: Sweep -- garbage-collect ephemeral artifacts

Targets

a) **dogfood-output directories**
   - Glob: `**/dogfood-output*/`
   - Knowledge extraction: scan each report.md for CRITICAL/HIGH findings not yet in devlog.
   - After extraction: delete the entire directory tree.

b) **Stale worktree artifacts**
   - Glob: `**/.claude/worktrees/*/`
   - CRITICAL: worktrees may contain unmerged code. Before recommending removal:
     * Check uncommitted files: `git -C  status --short`
     * Check unmerged patches: `git cherry origin/main ` for `+` lines.
   - SAFE (0 uncommitted, 0 unmerged): output `git worktree remove` command.
   - BLOCKED (has uncommitted or unmerged): SKIP. Tell user to run `/tidy --harvest` first.
   - NEVER recommend removing a worktree with uncommitted files or unmerged patches.

c) **Investigation reports in root or docs/**
   - Glob: `*-report.md`, `*-analysis.md`, `*-findings.md`, `*-investigation.md`,
     `*-recommendation.md`, `*-audit.md` in `./` and `./docs/`
   - Knowledge extraction: scan each file for Tier 1/2/3 content.
   - After extraction: delete the source file.
   - EXCEPTION: do NOT delete files referenced in docs/plan.md as active work.

d) **Versioned and dated report files** (--aggressive only)
   - Glob: `docs/*-v[0-9]*.md`, `docs/*-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]*.md`
   - Same treatment as investigation reports.

e) **Duplicate content across subrepos**
   - Check for identical .md files in multiple locations.
   - Report duplicates but do NOT auto-delete -- list them with recommended canonical location.

f) **.claude/scratch/ cleanup**
   - Glob: `.claude/scratch/**/*.md`
   - Scratch files older than 7 days with no references from plan.md.
   - Knowledge extraction before deletion (handled by Phase 2 if both phases run).

g) **Dead-code candidates (graph-based, REPORT-ONLY, opt-in via --dead-code)**
   - Requires `.code-review-graph/graph.db` at repo root and `code-review-graph` on PATH.
     If either is missing, SKIP with a note -- do not try to guess dead code from grep.
   - Freshness: run `code-review-graph detect-changes --brief`. If stale, run
     `code-review-graph update --skip-flows` first. A stale graph produces false positives
     in dead-code detection; never delete based on stale data.
   - For each non-test source node in the graph, call `query_graph` with pattern
     `callers_of`. Zero callers = dead-code candidate.
   - HEAVY filtering before reporting (false positives are high-risk):
     * Exclude symbols that match external-invocation patterns: HTTP/RPC/CLI/event
       handlers, init() functions, main() entries, exported SDK APIs, test entry points.
       Signals include: files in `cmd/`, `api/`, `routes/`, `handlers/`, `controllers/`,
       `bin/`; attributes/decorators like @app.route, @handler, gin.Handler; exported
       types in `sdk/`, `pkg/`, `lib/` directories; Go functions named `init`/`main`/
       `Test*`/`Benchmark*`/`Example*`.
     * Exclude symbols referenced via reflection or string lookup (grep the repo for
       the symbol name as a literal string -- any hit disqualifies it as "dead").
     * Exclude generated code (check file headers for "DO NOT EDIT" or similar).
     * Exclude symbols in communities with cross-community edges that terminate at them
       (these are likely externally-invoked even if the direct edge is not in the graph).
   - REPORT ONLY. Never delete source files or symbols. The tidy report lists the
     candidates with path, symbol name, file:line, and community. The user confirms
     each one and removes them via `/apply` (whose graph lane can verify the blast
     radius is truly zero before the change).
   - This target is OFF BY DEFAULT -- only runs when the user passes `--dead-code` along
     with `--sweep` (or no phase flag). `--apply` never auto-deletes source code; it only
     controls artifact deletion.

Sweep workflow (only if --apply for deletions)
1) Run all glob patterns.
2) For each match: record path, size, last modified, category.
3) Read docs/plan.md for the active references exclusion list.
4) Classify each file: EXT

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [dndungu](https://github.com/dndungu)
- **Source:** [dndungu/agent-skills](https://github.com/dndungu/agent-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-dndungu-agent-skills-tidy
- Seller: https://agentstack.voostack.com/s/dndungu
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
