agentleFS
timurgaleevtimurgaleev/vibestack/skills/vibe-gc/SKILL.md

vibe-gc

Skill8 starsChanged 6 months agoMITView on GitHub

Audit runtime roots for unused skills, orphan hooks, shadowed permissions and stale caches; soft-delete with undo.

The file

We split this skill into the rules it gives an agent

6 rules. About 0 are common, 1 is distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    If this session was compacted, the copy of this skill in context may be cut off.

    line 17
  2. Very specific:

    Read ${CLAUDE_SKILL_DIR}/SKILL.md from disk and resume at the step you are on.

    line 18
  3. Very specific:

    Use when the owner asks to clean up, slim down or audit what is installed around the agent: too many skills, noisy hooks, a long permission …

    line 22
  4. Very specific:

    If SESSION_KIND is headless or spawned, stop after Step 2: report the audit and move nothing.

    line 81
  5. Very specific:

    Only the last occurrence of a duplicate is removed, so one entry stays.

    line 162
  6. Distinctive:

    Unmeasured usage is not unused: Only a measured absence of use counts as a signal.

    line 188

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

If this session was compacted, the copy of this skill in context may be cut off. Read ${CLAUDE_SKILL_DIR}/SKILL.md from disk and resume at the step you are on.

When to invoke

Use when the owner asks to clean up, slim down or audit what is installed around the agent: too many skills, noisy hooks, a long permission list, a bloated ~/.claude, or a periodic (roughly monthly) configuration review. It is not for cleaning project source code, chat history or the pack's own skills — ./install already prunes skills the pack withdrew.

The skill is audit-only by default. Nothing moves until the owner confirms that one item, and every move is a soft delete with a logged undo.

{{include lib/snippets/session-host.md}}

Step 1: Scan

"${VIBESTACK_HOME:-$HOME/.vibestack}/bin/vibe-gc" scan --days 30

Each row is id channel path signal size_kb mtime confidence, ranked high → low, then by size, at most 20 rows. A shorter batch is the point: this runs periodically, not exhaustively. Show the rows as a numbered table. When the scan prints nothing, say the configuration is clean and stop.

What the channels mean:

  • skills — directories in ~/.claude/skills, ~/.agents/skills, ~/.cursor/skills, ~/.kiro/skills or ~/.copilot/skills ($COPILOT_HOME/skills when set) that the root's .vibestack-manifest does not claim. A missing or empty SKILL.md is high confidence; a name that repeats another root's skill is low. usage: unmeasured means no usage data exists for that root — it never makes an item more disposable.
  • hooks — scripts under ~/.claude/hooks/ that nothing in the user settings.json / settings.local.json and no other hook script references. A project's own .claude/settings.json is not read, so confirm before trashing a hook a project may call.
  • permissions — duplicate permissions.allow entries and Bash(...) entries already covered by Bash(*). The scan only reports them.
  • mcp — configured servers. The bin cannot see whether a server is live.
  • caches — file-history, shell-snapshots and the skills.old / skills.staging.* entries an interrupted install leaves beside a skills root, older than --days.

Step 2: Automation status

Build one table for the MCP servers and hooks the scan listed:

ItemConfiguredAuthenticatedRecently verifiedStale or brokenMissingEvidence

Fill the evidence column only from what this session observed. A server that failed to connect in this session is "stale or broken (this session)"; a server whose tools answered is "recently verified". A reference in a skill or a config entry is not proof that anything is live, and a failed connection is not proof that it is disposable — a server can be down for a day.

This skill never changes MCP, n8n, cron or launchd state. For an item that looks broken, name the owner's action (re-authenticate, restart the server, remove the entry by hand) instead of doing it.

Step 3: Confirm one item at a time

If SESSION_KIND is headless or spawned, stop after Step 2: report the audit and move nothing.

Otherwise walk the candidates in rank order. For each one, show its row and the evidence, then ask with AskUserQuestion:

  • Question: "Move <path> to the gc trash? Signal: <signal>."
  • Options: ["Trash it", "Skip", "Stop here"]

There is no "all" option, and one answer never covers the next item. Skip the mcp rows here — Step 2 already named the action. "Stop here" ends the walk; report what was done so far.

Step 4: Soft-delete the confirmed item

For a skill, hook or cache path:

"${VIBESTACK_HOME:-$HOME/.vibestack}/bin/vibe-gc" trash '<PATH from the row>'

For a repo row (an oversized log under a project's .vibestack/):

"${VIBESTACK_HOME:-$HOME/.vibestack}/bin/vibe-gc" trim '<PATH from the row>'

It keeps the last 256 KB and keeps the untrimmed original in ~/.vibestack/gc-trash/<date>/repo/; it refuses while that repository's browse daemon may be running, and for a log with no line break in its last 256 KB. undo does not restore a trim: the gc-log line names the original, and mv '<original>' '<log>' puts it back.

The bin moves it to ~/.vibestack/gc-trash/<date>/<channel>/ and appends an undo: line to ~/.vibestack/gc-log.md. A REFUSED: line means the path is settings, MCP configuration, transcripts, project state, a pack-owned skill or outside the known roots — nothing moved. Report the refusal; never move the path by other means.

For a permission entry, write the exact entry to ~/.vibestack/gc-entry.txt with the Write tool (no trailing newline), then run this with the settings file the row named:

_SETTINGS='<settings file path from the row>'
_DAY=$(date +%Y-%m-%d)
_VH="${VIBESTACK_HOME:-$HOME/.vibestack}"
_BACKUP="$_VH/gc-trash/$_DAY/permissions/$(basename "$_SETTINGS").$(date +%H%M%S)"
mkdir -p "$(dirname "$_BACKUP")" && cp "$_SETTINGS" "$_BACKUP" || { echo "BACKUP_FAILED"; exit 1; }
python3 -I -c '
import json, os, sys
settings, entry_file = sys.argv[1], sys.argv[2]
entry = open(entry_file, encoding="utf-8").read()
with open(settings, encoding="utf-8") as f:
    data = json.load(f)
allow = data.get("permissions", {}).get("allow", [])
if entry not in allow:
    sys.exit("ENTRY_NOT_FOUND")
i = len(allow) - 1 - allow[::-1].index(entry)
del allow[i]
# The new file takes the original mode, so the rename cannot widen a 0600 file.
fd = os.open(settings + ".gc-tmp", os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
os.fchmod(fd, os.stat(settings).st_mode & 0o7777)
with os.fdopen(fd, "w", encoding="utf-8") as f:
    json.dump(data, f, indent=2, ensure_ascii=False)
    f.write("\n")
' "$_SETTINGS" "$_VH/gc-entry.txt" || { echo "EDIT_FAILED"; exit 1; }
mv "$_SETTINGS.gc-tmp" "$_SETTINGS"
python3 -I -c '
import datetime, sys
log, settings, backup, entry_file = sys.argv[1:5]
entry = open(entry_file, encoding="utf-8").read()
ts = datetime.datetime.now().astimezone().isoformat(timespec="seconds")
with open(log, "a", encoding="utf-8") as f:
    f.write("- %s removed permission %r from %s; backup %s undo: cp %r %r\n" % (ts, entry, settings, backup, backup, settings))
' "$_VH/gc-log.md" "$_SETTINGS" "$_BACKUP" "$_VH/gc-entry.txt"
rm -f "$_VH/gc-entry.txt"
echo "REMOVED_FROM: $_SETTINGS"
echo "BACKUP: $_BACKUP"

Only the last occurrence of a duplicate is removed, so one entry stays. On BACKUP_FAILED, ENTRY_NOT_FOUND or EDIT_FAILED the settings file is unchanged — report it and go on to the next item.

Step 5: Report

vibe-gc — <date>
Moved:      <n> items (<reclaimed KB> KB)
  - <path> → <trash path>
Permissions removed: <n> (backups in gc-trash/<date>/permissions/)
Skipped:    <n>
Automation: <one line per server/hook with its status and the owner's action>
Undo:       "${VIBESTACK_HOME:-$HOME/.vibestack}/bin/vibe-gc" undo <date>   (moves that day's items back)
            permission edits: copy the backup named in gc-log.md over the settings file
Next review: <date + 30 days>

Important Rules

  • Audit-only by default. Nothing moves without a per-item confirmation in an interactive session.
  • Pack-owned skills are never candidates. A name in a root's .vibestack-manifest belongs to the pack; ./install manages it.
  • Stale is not disposable. A failed connection or an old timestamp is evidence to show, not a verdict.
  • Unmeasured usage is not unused. Only a measured absence of use counts as a signal.
  • Never hard-delete. The trash and the log are the undo path.
  • Sources and repos are never touched, nor MCP, n8n, cron or launchd state. The one exception is trim on a log under a repo's .vibestack/.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.