agentleFS
AraszArasz/ai-badger/skills/den-refresh/SKILL.md

den-refresh

Skill3 starsChanged 32 days agoMITView on GitHub

Use when an already-scaffolded project is behind the framework — a drift notice appeared, a new ai-badger version shipped, or the user asks to "refresh"/"update ai-badger". Reports what changed, backs up .ai-badger/, and re-scaffolds from the project's existing config.

The file

Show its rules and text

We split this skill into the rules it gives an agent

14 rules. About 0 are common, 3 are distinctive, and 11 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 11

    Very specific

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

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

    Add --prune-cache or --prune-namespaces only when the user has asked for it (steps 3 and 3c) — both delete from the user's home directory.

    line 50
  2. Very specific:

    If drift is found, re-scaffolds using the existing config.json

    line 58
  3. Very specific:

    Surface competing copies: When the report carries frameworkCopies, tell the user which trees exist and at what versions — a drift notice …

    line 117
  4. Very specific:

    only the links ai-badger placed are removed.

    line 153
  5. Very specific:

    Review the diff: After re-scaffold, git diff shows exactly what changed.

    line 160
  6. Distinctive:

    If the config needs updating (new stacks, changed commands), edit it first, then run den-refresh.

    line 182
  7. Distinctive:

    When a refresh reports dropped content, that is the fix to offer (Why — see Gotchas.).

    line 196
  8. Very specific:

    Stack ignore list: If .ai-badger/stack-ignore.json exists, stacks listed in its ignore array are excluded from newStacks detection.

    line 197
  9. Very specific:

    Use this to suppress false-positive stack detection (e.g.

    line 199
  10. Very specific:

    If the project's config.json is invalid, den-refresh exits with an error.

    line 234
  11. Very specific:

    If index.json is missing or stale in the framework checkout, run python3 "$AI_BADGER/tooling/index_build.py" first.

    line 237
  12. Very specific:

    When refresh.py exits non-zero or returns JSON with an error field, attempt recovery before surfacing the failure to the user.

    line 255
  13. Distinctive:

    After applying a fix, re-run the refresh.

    line 266
  14. Very specific:

    Recovery failed — offer to create a GitHub issue: Follow .ai-badger/skills/welcome-ai-badger/references/reporting-a-framework-bug.md when a …

    line 269

≈ “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

den-refresh

Pulls framework updates from the ai-badger catalog into a project that was already scaffolded. The script does all mechanical work; you (the agent) present the report and help the user review the diff.

This is the update direction of the framework: framework → project (update). For initial setup use welcome-ai-badger; to contribute back use feed-badger.

Responsibility split

  • Script (mechanical): refresh.py validates prerequisites (config.json, manifest.json), runs drift detection, re-scaffolds with the existing config, and emits a JSON report. Skills with extensions (e.g., task with github/hermes extensions) are re-scaffolded and their extensions re-embedded automatically.
  • You (creative only): present the report, help the user review what changed, and offer to commit or discard. There is no config authoring, no stack detection, no plugin scope prompt — those belong to welcome-ai-badger.

Prerequisites

  • Project has .ai-badger/config.json and .ai-badger/manifest.json (it was scaffolded by welcome-ai-badger)
  • An ai-badger framework checkout is accessible ($AI_BADGER)

Flow

  1. Run refresh. From the target repo root:

    python3 "$AI_BADGER/features/common/skills/den-refresh/scripts/refresh.py" --target . --root "$AI_BADGER"

    Add --prune-cache or --prune-namespaces only when the user has asked for it (steps 3 and 3c) — both delete from the user's home directory. Add --force only as recovery (see Error Recovery) — it re-scaffolds unconditionally, bypassing every drift signal. This:

    • Validates that config.json and manifest.json exist
    • Reads the manifest to extract scaffolded skill names
    • Runs drift detection against the framework's current content
    • If drift is found, re-scaffolds using the existing config.json
    • Outputs a JSON report with drift details and scaffold notes

    Exit codes: 0 = success (up to date or changes applied), 2 = error (missing config/manifest, invalid config).

  2. Review the report. The JSON output includes:
    • frameworkVersion — the version in config.json vs. the framework's, plus the version that actually wrote manifest.json. config.json advances only when a re-scaffold ran
    • drift.changed — framework sources that have moved ahead of what this project holds
    • drift.removed — scaffolded files whose framework source no longer exists
    • drift.orphaned — entries whose stack this project no longer lists in config.stacks. The framework still ships them; this project stopped asking. The re-scaffold prunes them, leaving anything edited in place with a note
    • drift.versionChanged — the version alone moved; it is stamped into manifest.json and every generated agent file, so those are stale even when no content changed
    • drift.locallyModified — skills this project edited in place. Not framework drift, but a re-scaffold overwrites them; move anything worth keeping into project-local.md
    • drift.skipped — directory entries from a manifest written before source hashing existed. Nothing records what the framework looked like, so they cannot be compared; a re-scaffold makes them comparable
    • drift.newItems — catalog items the project has never scaffolded, including ones added to the framework's always-on common stack after this project was set up
    • drift.configChanged — null unless config.json itself no longer matches what the last scaffold was built from (an exclude, commands, stacks, agents or personaRouting edit). Present as {"recorded": ..., "current": ...}; recorded: null means this manifest predates the field and self-heals on this one re-scaffold
    • drift.proseReview — the config's free-form prose (project.summary, project.domain), re-rendered verbatim into the managed agent files on every scaffold and checked by no fingerprint, so it goes stale silently. Each entry names the configKey, the template slot it fills, the value as written, and carries the note "human-written — review for staleness". Present them to the operator for review; never treat them as drift — a re-scaffold cannot freshen prose, only re-render it, and config.json is project-owned
    • newStacks — stacks detectable in the target but missing from config. Advisory only: it never triggers a re-scaffold, so non-empty newStacks alongside reScaffolded: false is the expected shape, not a contradiction
    • reScaffolded — whether a re-scaffold was performed
    • projectIdWarning — present only when the project-id step warned: ai-raccoon's id lookup or registration failed, several bank projects share this repo's name, or the reply was unusable. The id file is still minted or kept; the warning names the command to rerun after a human resolves it (ai-raccoon 1.57.0's project id verbs; ADR-0036)
    • note — present only when config.json and the framework disagree on the version and no re-scaffold ran; the generated files were not rewritten, so say so rather than reporting green
    • scaffold — if re-scaffolded: entry count, refreshed skill names, notes
    • frameworkCopies — present only when more than one tree on the machine claims to be ai-badger, or when ~/.ai-badger/framework exists. competing names the path, version and owner of each; cache reports what happened to ~/.ai-badger/framework (reported by default, removed with --prune-cache, refused with the reason)
    • skillUsage — which delivered skills this project was observed using, so unused ones can be pruned from the listing budget (see step 3b). used / unused / cannotTell, plus the window the claim rests on, the channels that answered, and the limits of both
    • hermesNamespaces — present only when every ai-badger symlink in a ~/.hermes/skills/<project>/ directory is dangling: that project's .ai-badger/skills/ tree is gone. Every project's namespace is swept, not just this one (see step 3c). Each entry carries path, links (dead links ai-badger placed), kept (entries it did not — a non-zero kept means the directory itself survives the prune), the target that no longer exists, and status (reported by default, removed with --prune-namespaces, failed with the reason)
  3. Surface competing copies. When the report carries frameworkCopies, tell the user which trees exist and at what versions — a drift notice fires once per tree, so two contradictory notices mean two installs, not a framework bug. ~/.ai-badger/framework is ai-badger's own fallback clone and nothing updates it in place; offer to re-run with --prune-cache to remove it. Never offer to delete ~/.claude/plugins/cache/ — Claude Code owns that path and ai-badger only reads it.

3b. Offer the prune candidates — never prune them. skillUsage.unused names skills this project holds and nobody invoked over skillUsage.window. The payoff is the listing budget: a host allots a fixed slice of context to skill descriptions and drops the least-invoked ones first, so an unused skill crowds one somebody does use. Tell the user the candidates and how to decline them — exclude.skills in config.json, which is self-executing on the next refresh (drift.configChanged) — and stop there. config.json is project-owned; never edit it as part of a refresh.

Report the rest of the section with the candidates, not instead of them:

  • used carries evidence — invocation (someone ran it) or hook (nobody ran it, but a hook it ships fired, so it is doing work every session). Both mean leave it alone
  • cannotTell is the honest bucket, and it is not a weaker unused: a skill listed there was never observable. Never propose pruning one
  • window.days bounds every claim. A short window and a quarterly skill produce a confident-sounding recommendation that is simply wrong — say the number out loud
  • limits states what the channels cannot see. Repeat it; a recommendation without it is the one the user will regret
  • hint, when present, replaces the recommendation: nothing could be observed, and the fix it names (behaviorist.py on 4h, then work normally) is the whole answer

3c. Present the orphaned namespaces and ask. When the report carries hermesNamespaces, list each path with its links count and the target that no longer exists, then ask the user whether to remove them. Only on a yes, re-run the command with --prune-namespaces. Never pass the flag on your own initiative — a namespace can dangle because its project sits on a drive that is not mounted right now, and a refresh that deletes it takes the user's Hermes skill wiring with it. Two things to say out loud:

  • the sweep covers every project's namespace, not just this one. That is deliberate — an orphan's project no longer exists to run den-refresh in, so nothing else will ever reach it — but it means the paths named may belong to work the user has forgotten
  • only the links ai-badger placed are removed. Anything else in that directory — a Hermes-authored skill, a link pointing outside a .ai-badger/skills/ tree — stays, and the directory stays with it: that is what a non-zero kept means. A directory holding no ai-badger link at all, such as a Hermes category like react or uncategorized, is never listed and never touched. If the user expected one of those gone, it is theirs to delete by hand
  1. Review the diff. After re-scaffold, git diff shows exactly what changed. Seed-once files (state.json, markers-context.json, model.json) are preserved and won't appear in the diff unless they were mutated by the project before the refresh.
  2. Commit or discard. Managed files should be committed to pick up the framework updates. Seed-once files are project-owned and never overwritten.

How it differs from welcome-ai-badger

welcome-ai-badgerden-refresh
When to useFirst time setupSubsequent updates
DetectionRuns detect.pyReads existing config
ConfigAgent authors new config.jsonUses existing config.json
QuestionsAsks for summary, domain, persona routing, plugin scopeNo questions
Plugin installRuns plugin install commandsSkips plugin install
SkillsScaffolds from the skill listExtracts skill names from manifest

Rules

  • Never re-detect. den-refresh uses the project's existing config.json as-is. If the config needs updating (new stacks, changed commands), edit it first, then run den-refresh. Exception: den-refresh detects stacks that have signals in the target but are missing from config, and reports them as newStacks — advisory only, it never gates the re-scaffold (#134). Two paths from there, both project-owned: accept — add the stack to config.stacks and re-run; the edit itself is drift (configChanged, #128), so the re-scaffold that delivers it is self-executing. Decline — add it to .ai-badger/stack-ignore.json; never overwritten by a re-scaffold.
  • Seed-once files survive. state.json, markers-context.json, and model.json are seed-once and preserved across re-scaffolds (Why — see Gotchas.).
  • Preserved regions survive. Managed agent files (CLAUDE.md, .ai-badger/CLAUDE.md, AGENTS.md, the Copilot and Hermes files) are regenerated in full, so project-authored content in them is dropped unless it sits between <!-- ai-badger:keep-start --> and <!-- ai-badger:keep-end -->. When a refresh reports dropped content, that is the fix to offer (Why — see Gotchas.).
  • Stack ignore list. If .ai-badger/stack-ignore.json exists, stacks listed in its ignore array are excluded from newStacks detection. Use this to suppress false-positive stack detection (e.g. python detected because .mcp.json references python3 for a tool dependency). The file is project-owned (manual) and never overwritten by re-scaffold.
  • Skills with extensions are refreshed. The script extracts skill names from the manifest, so skills like task (with github/hermes extensions) are re-scaffolded and their extensions re-embedded.
  • Managed files are overwritten. Everything else under .ai-badger/ that the framework originally placed is refreshed to the framework's current content. Review the diff before committing.
  • Usage evidence has two sources and one of them cannot prove absence. The invocation channel reads Claude Code's own transcript store (~/.claude/projects/<mangled cwd>/*.jsonl, this project's sessions and its worktrees) for Skill calls and slash commands — any skill, but only on that host, and only as far back as Claude Code retains transcripts. The hook channel reads call-behaviorist's audit log, which records hooks, so it can confirm a skill is working and never that one is idle. Only the invocation channel produces a prune candidate; with no transcript store, every skill lands in cannotTell and the report recommends nothing. Neither channel reads message content — skill names and timestamps only.
  • Only ~/.ai-badger/framework is ever pruned, and only on request. ai-badger created that clone, so it may remove it — never silently, only under --prune-cache, never when it is the root in use, and never when the path is a symlink or holds one that leaves it. Every other tree (Claude Code's plugin cache, a framework checkout) is reported and left alone: no command destroys state it did not create.

Gotchas

  • Seed-once files survive. state.json, markers-context.json and model.json are preserved across re-scaffolds — a refresh never resets them.
  • Preserved regions are the only survival path. Managed agent files are regenerated in full; project-authored content in them is dropped unless it sits between <!-- ai-badger:keep-start --> and <!-- ai-badger:keep-end -->.
  • Absence is not a declaration. A deleted skill, persona, invariant or instruction comes back on the next refresh — add its name to exclude in config.json to decline it for good.

Notes

  • If the project's config.json is invalid, den-refresh exits with an error. Fix the config first (re-run welcome-ai-badger steps 2-4 if needed), then run den-refresh.
  • If index.json is missing or stale in the framework checkout, run python3 "$AI_BADGER/tooling/index_build.py" first.
  • den-refresh delegates to the same scaffold.py that welcome-ai-badger uses — the re-scaffold is identical to an initial scaffold, just driven by an existing config.
  • A deleted skill, persona, invariant or instruction comes back: absence is not a declaration (Why — see Gotchas.). To decline one for good, add its name to exclude in config.json ({"skills": ["mcp-index"]}) and re-run den-refresh — the edit is self-executing (drift.configChanged, #128), so no separate step is needed. The refresh then stops delivering it and removes the discovery symlinks ai-badger placed for it. The same applies to any other config-only edit: commands, personaRouting, agents, stacks.
  • Dropping a stack from config.stacks is the other way to stop asking, and it now converges the same way: the entries that stack delivered are reported as drift.orphaned and pruned by the re-scaffold. Before 0.42.0 the removal was invisible and the files were left behind (#116).

Error Recovery

When refresh.py exits non-zero or returns JSON with an error field, attempt recovery before surfacing the failure to the user.

  1. Parse the error. The script emits structured JSON — read the error field and any validationErrors array to classify the failure.
  2. Attempt automatic recovery. Try the applicable fix, then re-run the refresh command from step 1 of the Flow.

    Fix table: read references/error-recovery.md when refresh.py exits non-zero or returns a JSON error field.

    After applying a fix, re-run the refresh. If it succeeds, report what was fixed and continue with the normal flow (review diff, commit).

  3. Recovery failed — offer to create a GitHub issue. Follow .ai-badger/skills/welcome-ai-badger/references/reporting-a-framework-bug.md when a fix does not recover the failure: ask permission first, gate on gh being installed and authenticated, sanitize the config before including it. Never create the issue without explicit user approval — that rule holds even if the reference file is not present.

Verification Checklist

  • refresh.py exited 0
  • Report read section by section: frameworkVersion, drift.*, reScaffolded, note, frameworkCopies, hermesNamespaces
  • Competing copies surfaced; ~/.ai-badger/framework pruned only on request
  • Orphaned Hermes namespaces presented and the user asked; --prune-namespaces passed only on a yes
  • Prune candidates offered, never pruned — config.json untouched
  • Diff reviewed before commit
  • Seed-once files (state.json, markers-context.json, model.json) absent from the diff

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.