skill-tracker
Check and apply upstream updates to installed skills. Reads pending-updates.json generated by the cron checker, spawns haiku agents to evaluate each diff for quality and safety, then spawns sonnet age
Files1
View on GitHubSKILL.mdskills/skill-tracker/SKILL.md
GitHub/skill-update — Skill Version Tracker & Auto-Updater
Reviews upstream updates for installed skills. Uses haiku agents to evaluate diffs, sonnet agents to apply smart merges. Never overwrites local customizations.
File Locations
${CLAUDE_SKILL_DIR}/
├── source-registry.json ← tracked repos + last-known commit SHAs
├── pending-updates.json ← generated by cron check-versions.ts
└── update-history.md ← log of applied updates
Step 0: Check Pending Updates
cat ${CLAUDE_SKILL_DIR}/pending-updates.json 2>/dev/null
If the file is missing or pending array is empty:
- Run the checker manually first:
npx tsx ${CLAUDE_SKILL_DIR}/check-versions.ts - If still empty after running: output "All tracked skills are up to date." and stop.
Show a summary table of pending updates before proceeding:
SKILL REPO POLICY COMMITS
humanizer blader/humanizer haiku_evaluate 8b3a → def456 (2026-05-10)
lightpanda lightpanda-io/agent-skill haiku_evaluate bc56 → 9a3f (2026-05-08)
animejs (+ 12 more) heygen-com/hyperframes haiku_evaluate 94b8 → new (2026-05-09)
Step 1: Handle always_prompt Skills First
For any skill with update_policy: "always_prompt" (Vietnamese marketing skills):
- Download upstream SKILL.md for each one
- Show a unified diff in the terminal
- AskUserQuestion: "Update {skill-name}? Diff shown above." Options: ["Apply update", "Skip this one"]
- If Apply: proceed to sonnet merge (Step 4) for that skill
- If Skip: add to skipped list
Step 2: Handle notify_only Skills
For skills with update_policy: "notify_only" (e.g., markitdown — upstream is a library, not a SKILL.md):
- Output: "⚠️ {repo} has upstream changes since {date}. SKILL.md is hand-written — review manually if needed."
- Update
installed_commitin registry to latest (so it stops appearing every cycle) - Do not attempt to update the SKILL.md
Step 3: Haiku Evaluation — Spawn in Parallel
For all skills with update_policy: "haiku_evaluate":
3a. For update_via: github_api skills — download upstream SKILL.md:
curl -sL "{upstream_skill_url}" -o /tmp/skill-upstream-{skill}.md
3b. For update_via: npx_skills skills — get the upstream content via npx dry-check:
# Check what npx skills update would download
npx skills update {skill-name} --dry-run 2>/dev/null
If dry-run output shows content, use it. Otherwise skip the haiku eval and trust npx.
3c. Spawn haiku agents in parallel (one per skill, all in one message):
Each haiku agent receives this prompt:
You are evaluating whether a skill update should be applied.
LOCAL VERSION (current):
---
{content of local_skill_path}
---
UPSTREAM VERSION (new):
---
{content of /tmp/skill-upstream-{skill}.md}
---
Score this update on 4 axes (1-10 each):
1. new_capabilities: Does upstream add new sections, commands, or patterns not in local?
2. bug_fixes: Does upstream fix incorrect instructions or broken patterns?
3. local_value: Does local have custom content NOT in upstream (integrations, project-specific notes)?
IMPORTANT: If local_value is high (≥7), this argues AGAINST a FULL update — use MERGE instead.
4. regression_risk: Does upstream REMOVE useful content that local has?
overall_score = (new_capabilities + bug_fixes - regression_risk) / 3
Return ONLY valid JSON (no explanation):
{
"skill": "{skill}",
"new_capabilities": N,
"bug_fixes": N,
"local_value": N,
"regression_risk": N,
"overall_score": N,
"verdict": "SKIP|MERGE|FULL",
"reason": "one sentence",
"new_sections": ["section title or description if any"],
"preserve_sections": ["section title or description if any"]
}
Verdict rules:
- FULL: overall_score ≥ 7 AND local_value < 4 AND regression_risk < 3
- MERGE: overall_score ≥ 4 AND (local_value ≥ 4 OR regression_risk ≥ 3)
- SKIP: overall_score < 4 OR (regression_risk ≥ 7 AND local_value ≥ 6)
Collect all haiku verdicts.
3d. Show verdict table:
SKILL SCORE VERDICT REASON
humanizer 6.3 MERGE Upstream adds 3 new AI-tell patterns; local has org-specific rules
lightpanda 8.1 FULL Major update: new MCP server config, CDP examples; local is vanilla
animejs 3.2 SKIP Only timestamp changes, no new content
AskUserQuestion: "Proceed with applying {N} updates? (FULL: {n}, MERGE: {n}, SKIP: {n} already excluded)" Options: ["Yes, apply all", "Review each one", "Skip all for now"]
If "Review each one": for each MERGE/FULL skill, show diff and ask individually.
Step 4: Apply Updates — Sonnet Agents in Parallel
For each skill with verdict MERGE or FULL (after user confirmation):
Spawn one sonnet agent per skill (all in a single message):
You are applying a skill update for "{skill}".
VERDICT: {FULL|MERGE}
LOCAL PATH: {local_skill_path}
UPSTREAM URL: {upstream_skill_url}
LOCAL CONTENT:
---
{local content}
---
UPSTREAM CONTENT:
---
{upstream content}
---
PRESERVE SECTIONS (identified by haiku): {preserve_sections}
NEW SECTIONS (to add from upstream): {new_sections}
INSTRUCTIONS:
1. BACKUP first: copy local file to ~/.claude/skills/_sync/backups/{skill}/{ISO-timestamp}/SKILL.md
2. If verdict=FULL: write upstream content as-is to {local_skill_path}
3. If verdict=MERGE:
a. Start with upstream as the base
b. Identify sections in local that are NOT in upstream (local customizations)
c. Append those local-only sections at the end of the upstream content, under a heading:
"## Local Additions (preserved from previous version)"
d. Write the merged content to {local_skill_path}
4. Verify the file was written correctly (read it back)
5. Report: DONE — {skill}: {FULL|MERGE} applied, {n} local sections preserved
DO NOT:
- Delete any section that existed in local and has meaningful content
- Modify the frontmatter name/description/triggers fields without good reason
- Add "## Local Additions" header if there are no local-only sections
Step 5: Update Registry + Log
After all sonnet agents complete:
For each updated skill, find its repo in
source-registry.json:- Set
installed_commit=upstream_commitfrom pending-updates.json - Set
installed_commit_date=upstream_commit_date - Set
latest_upstream_commit= null (cleared — no longer pending) - Set
last_checked= today
- Set
Clear
pending-updates.json(setpending: [])Append to
${CLAUDE_SKILL_DIR}/update-history.md:
## {YYYY-MM-DD}
| Skill | Repo | Verdict | Action |
|---|---|---|---|
| humanizer | blader/humanizer | MERGE | 3 local sections preserved, 2 new patterns added |
| lightpanda | lightpanda-io/agent-skill | FULL | Updated to latest |
| animejs | heygen-com/hyperframes | SKIP | No meaningful changes |
Step 6: Final Summary
✅ SKILL UPDATE COMPLETE
Updated: humanizer (MERGE), lightpanda (FULL)
Skipped: animejs, css-animations (no meaningful changes)
Prompted: marketing/01-lich-noi-dung (user skipped)
Registry updated. Next check in ~4 days (cron: 0 2 */4 * *).
Backups at: ~/.claude/skills/_sync/backups/
Manual Run (outside cron)
To check versions right now without waiting for cron:
npx tsx ${CLAUDE_SKILL_DIR}/check-versions.ts
Then invoke /skill-update to review.
Adding New Repos to Track
Edit ${CLAUDE_SKILL_DIR}/source-registry.json:
- Add a new entry under
reposwith the GitHub repo slug as key - Set
track: true,update_via: "github_api"or"npx_skills" - Set
installed_commitby running:curl -sL "https://api.github.com/repos/{repo}/commits?per_page=1" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d[0]['sha'][:12])" - Run
/skill-updateto pick it up immediately
What's Not Tracked
- VoltAgent (56 skills): upstream repo returns 404 — cannot track
- manual/auto-registered (135 skills): hand-written, no upstream
- gstack core (53 bundled): use
/gstack-upgradefor those