Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Config Gc

ASecurity

Garbage collection for the active Claude config root — scans skills, memory, hooks, permissions, MCP servers, and caches for redundant, stale, or orphaned items, then walks the user through confirm-each-deletion cleanup. Use on "clean up my config", "config GC", "too many skills", "my .claude is bloated", or a periodic review.

2 stars
0 votes
0 copies
0 views
Added 9/19/2026
developmentgoshellbashrefactoringgitfrontendsecurity

Works with

claude codemcp

Security Analysis

A100/100

Scanned 9/19/2026

Install to Claude Code

$npx -y skills add AndrewDongminYoo/cc-agents-kit --skill config-gc --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Config Gc?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Config Gc
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/andrewdongminyoo-config-gc/badge)](https://www.skillsdirectory.com/skills/andrewdongminyoo-config-gc)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: config-gc
description: Garbage collection for the active Claude config root — scans skills, memory, hooks, permissions, MCP servers, and caches for redundant, stale, or orphaned items, then walks the user through confirm-each-deletion cleanup. Use on "clean up my config", "config GC", "too many skills", "my .claude is bloated", or a periodic review.
metadata:
  category: claude-config
  origin: https://github.com/affaan-m/ecc (MIT), skills/config-gc — substantially upstream; see CREDITS.md
---

# Config GC — Garbage Collection for Claude Code Setups

Borrowed from runtime garbage collection: periodically scan for objects that are no longer referenced, redundant, expired, or low-value, and reclaim the space. The critical difference: **here, collection requires a human in the loop. Never delete autonomously.**

## When to Activate

- The user asks to clean up, audit, or slim down their Claude Code configuration
- The user complains about too many skills, noisy hooks, or slow session startup
- A monthly/periodic config review is due
- After installing a large skill pack (e.g. this repo), to reconcile overlaps with existing setup

Do NOT activate for: cleaning project source code (that's refactoring), clearing chat history, or uninstalling Claude Code itself.

## Active Config Root

Derive one root at the start of the run and use it for every scan, backup, soft-delete, and log operation:

```bash
ACTIVE_CONFIG_ROOT="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
```

Do not scan both the default and an override.
When `CLAUDE_CONFIG_DIR` is set, it is the active root; otherwise use `$HOME/.claude`.

## Design Philosophy

1. **Append-only configs leak.** Skills, memory files, hooks, and permission entries only ever get added. Without periodic review they rot silently.
2. **Regular audits beat one-time purges.** Scan every ~30 days, propose a small batch of candidates each time.
3. **Per-channel strategies.** Each accumulation type (skills, hooks, permissions, ...) has its own staleness signals — don't apply one rule everywhere.
4. **Soft-delete first.** Rename to `.disabled` > move to `$ACTIVE_CONFIG_ROOT/_gc_trash/` > real deletion. Always keep an undo path.
5. **Forced human-in-the-loop.** Every candidate gets its own `[y/n/skip]` confirmation. No "yes to all" shortcut.
6. **Keep a log.** Every GC run appends to `$ACTIVE_CONFIG_ROOT/gc_log.md`: what was touched, why, and how to undo it.

## Scan Channels

| #   | Channel                    | Path                                                           | Staleness / redundancy signals                                                                                                                                                    |
| --- | -------------------------- | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1   | Skills                     | `$ACTIVE_CONFIG_ROOT/skills/*/`                                | Heavily overlapping names; never triggered in recent transcripts; domain mismatch with the user's actual work; broken or empty SKILL.md                                           |
| 2   | Memory                     | `$ACTIVE_CONFIG_ROOT/**/memory/*.md` + its index               | Multiple index entries for one topic; contents contradicting newer entries; dates that have passed; orphan files missing from the index; sub-100-word fragments that should merge |
| 3   | Hooks                      | `$ACTIVE_CONFIG_ROOT/hooks/` + settings                        | Scripts present on disk but referenced by no hook config; old versions superseded by rewrites                                                                                     |
| 4   | Permissions                | `permissions.allow` in `settings.json` / `settings.local.json` | Duplicate entries; specific entries already covered by a wildcard (e.g. `Bash(git push)` when `Bash(*)` is allowed); one-off grants from past experiments                         |
| 5   | MCP servers                | `$ACTIVE_CONFIG_ROOT/.claude.json` or `.mcp.json` records      | Servers that fail to connect; functional duplicates; long-unused                                                                                                                  |
| 6   | Scheduled reminders / jobs | job metadata referenced from `$ACTIVE_CONFIG_ROOT`             | Fired one-shots older than 30 days; jobs whose target scripts no longer exist                                                                                                     |
| 7   | Project history            | `$ACTIVE_CONFIG_ROOT/projects/*/`                              | Stale handoff snapshots; session records superseded by newer state                                                                                                                |
| 8   | Runtime caches             | `cache/`, `file-history/`, `logs/`, `shell-snapshots/`         | Sort by size and mtime; propose items >30 days old and large                                                                                                                      |

## Workflow

1. **Scan** all channels (or the subset the user names). Collect candidates with: path, channel, signal that flagged it, size, last-modified.
2. **Rank** by confidence (broken/orphaned = high; merely old = low) and present as a numbered table. Cap each run at ~20 candidates — GC is periodic, not exhaustive.
3. **Confirm one by one.** For each candidate show the evidence, then ask `[y/n/skip]`. The user can stop at any point.
4. **Soft-delete confirmed items**: prefer `.disabled` rename for skills/hooks and `_gc_trash/<date>/` move for files. Permission entries live in JSON (no comments possible): back up the settings file, record each removed entry verbatim in `gc_log.md`, then remove it from the `allow` array with `jq`. Only hard-delete when the user explicitly asks.
5. **Log** the run to `$ACTIVE_CONFIG_ROOT/gc_log.md`: timestamp, items actioned, undo instructions.
6. **Report**: reclaimed size, channels still healthy, suggested next review date.

## Example Scan Commands

Orphaned hook scripts (channel 3) — scripts on disk that no hook config references.
**Grep each settings file separately.** `settings.local.json` is often absent, and on macOS/BSD an unreadable file makes grep exit 2 even when the pattern matched in the file that does exist — one missing file then reports every script as an orphan:

```bash
ACTIVE_CONFIG_ROOT="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
for f in "$ACTIVE_CONFIG_ROOT"/hooks/* "$ACTIVE_CONFIG_ROOT"/scripts/*; do
  [ -f "$f" ] || continue
  name=$(basename "$f") hit=""
  for cfg in "$ACTIVE_CONFIG_ROOT/settings.json" "$ACTIVE_CONFIG_ROOT/settings.local.json"; do
    [ -f "$cfg" ] && grep -qF "$name" "$cfg" && hit=1
  done
  [ -n "$hit" ] || echo "ORPHAN: $f"
done
```

Then clear each hit by hand before proposing it: a script can be wired somewhere settings.json never mentions — a launchd plist, another skill, a README, or "manual by design". Confirm where it is called from, not merely that settings.json omits it.

Redundant permission entries (channel 4) — duplicates, and specific grants shadowed by a wildcard.
Both settings files are optional, so guard the read; `jq` on a missing path aborts the pipeline:

```bash
ACTIVE_CONFIG_ROOT="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
for cfg in "$ACTIVE_CONFIG_ROOT/settings.json" "$ACTIVE_CONFIG_ROOT/settings.local.json"; do
  [ -f "$cfg" ] || continue
  echo "-- $cfg"
  jq -r '.permissions.allow[]?' "$cfg" | sort | uniq -d
  if jq -e '.permissions.allow? | index("Bash(*)")' "$cfg" >/dev/null 2>&1; then
    jq -r '.permissions.allow[]?' "$cfg" | grep '^Bash(' | grep -vF 'Bash(*)'
  fi
done
```

Stale plugin cache versions (channel 8) — `plugins/cache/<marketplace>/<plugin>/<version>/` keeps every version ever synced, while `installed_plugins.json` names the one in use.
Marketplaces that version by git SHA mint a fresh directory on every upstream commit, so this grows without bound:

Key the lookup on the full `plugin@marketplace` id, never on the plugin name alone — the same plugin name ships from more than one marketplace (`commit-commands` and `frontend-design` each exist twice here), and a name-only match reports the surviving twin's version as current for the uninstalled one:

```bash
ACTIVE_CONFIG_ROOT="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
cd "$ACTIVE_CONFIG_ROOT"
for pdir in plugins/cache/*/*/; do
  mp=$(basename "$(dirname "$pdir")"); plugin=$(basename "$pdir")
  cur=$(jq -r --arg k "$plugin@$mp" '.plugins[$k][0].version // empty' plugins/installed_plugins.json)
  if [ -z "$cur" ]; then echo "ORPHAN DIR (plugin uninstalled): $pdir"; continue; fi
  for v in "$pdir"*/; do
    [ "$(basename "$v")" = "$cur" ] || echo "STALE: $v"
  done
done
```

Before proposing a cached plugin directory, verify its `installPath` also resolves under `$ACTIVE_CONFIG_ROOT`; a mismatched record is evidence to investigate, not permission to delete another root.

Largest stale caches (channel 8) — `du -k` instead of GNU-only `find -printf`, so it works on macOS/BSD too:

```bash
ACTIVE_CONFIG_ROOT="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
find "$ACTIVE_CONFIG_ROOT/file-history" "$ACTIVE_CONFIG_ROOT/shell-snapshots" -type f -mtime +30 \
  -exec du -k {} + 2>/dev/null | sort -rn | head -20
```

Soft-delete with undo path (capture the date once so the log can't disagree with the directory):

```bash
ACTIVE_CONFIG_ROOT="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
gc_date=$(date +%Y-%m-%d)
mkdir -p "$ACTIVE_CONFIG_ROOT/_gc_trash/$gc_date"
mv "$ACTIVE_CONFIG_ROOT/skills/dead-skill" "$ACTIVE_CONFIG_ROOT/_gc_trash/$gc_date/"
echo "$(date -Iseconds) moved skills/dead-skill -> _gc_trash/$gc_date/ (undo: mv back)" >> "$ACTIVE_CONFIG_ROOT/gc_log.md"
```

Removing a confirmed-redundant permission entry (JSON has no comments — back up, log, then edit):

```bash
ACTIVE_CONFIG_ROOT="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
cp "$ACTIVE_CONFIG_ROOT/settings.local.json" "$ACTIVE_CONFIG_ROOT/settings.local.json.bak"
echo "$(date -Iseconds) removed permission entry: Bash(git push) (undo: restore from .bak or re-add)" >> "$ACTIVE_CONFIG_ROOT/gc_log.md"
jq '.permissions.allow -= ["Bash(git push)"]' "$ACTIVE_CONFIG_ROOT/settings.local.json.bak" \
  > "$ACTIVE_CONFIG_ROOT/settings.local.json"
```

## Anti-Patterns

- **Bulk approval.** Asking "delete all 15? [y/n]" defeats the design. One item, one decision.
- **Hard-deleting on first pass.** If there's no `_gc_trash/` copy or `.disabled` rename, you did it wrong.
- **Treating "old" as "dead".** A skill untouched for 60 days may be seasonal (tax season, quarterly reviews). Age is a signal, not a verdict — that's why a human confirms.
- **Cleaning memory by truncation.** Merging two contradicting memory files requires reading both and keeping the newer truth, not deleting the longer one.
- **Touching anything outside `$ACTIVE_CONFIG_ROOT`.** Config GC never wanders into another config root or a source tree.

## Best Practices

- Run after big additions, not just on a calendar: installing a 50-skill pack is exactly when overlap with existing skills appears.
- When two skills overlap, prefer disabling the one with the weaker trigger description — it's the one that was probably never firing anyway.
- Permission cleanup is the highest-value channel per minute spent: redundant allow-entries make security review harder.
- Keep `gc_log.md` forever. It's tiny, and "when did I disable that hook and why" comes up more often than you'd think.

## Related Skills

- `fewer-permission-prompts` — the additive counterpart for the permissions channel: it grants, config-gc prunes.
- `audit-knowledge-drift` — audits doc/memory _accuracy_; config-gc audits _existence_. Run it on what survives GC.
- `context-budget` — audits the _context cost_ of what remains loaded; config-gc decides what exists at all.

## Provenance

Vendored from [affaan-m/ecc](https://github.com/affaan-m/ecc) (MIT) on 2026-07-17; maintained locally since — Related Skills rewritten to point at this setup's counterparts.

Attribution

AndrewDongminYooAndrewDongminYoo
View sourceMore from AndrewDongminYoo →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

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 (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

281612 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2132 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →