quot;; then brew upgrade "$formula_short" fi done ``` **Go**: Reinstall with `@latest` (Go modules are idempotent) ```bash for module in "${GO_MODULES[@]}"; do bin_name="${module##*/}" bin_name="${bin_name%@*}" go install "$module" done ``` **Node**: Use `npm update -g` ```bash for package in "${NODE_PACKAGES[@]}"; do npm update -g "$package" done ``` ## Scheduling with LaunchAgent The script runs weekly via macOS LaunchAgent. Create `~/Library/LaunchAgents/com.bioinfo.skills-updater.plist`: ```xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.bioinfo.skills-updater</string> <key>ProgramArguments</key> <array> <string>/Users/bioinfo/scripts/skills-updater.sh</string> <string>--quiet</string> </array> <key>StartCalendarInterval</key> <dict> <key>Weekday</key> <integer>0</integer> <key>Hour</key> <integer>4</integer> </dict> <key>EnvironmentVariables</key> <dict> <key>PATH</key> <string>/opt/homebrew/bin:/usr/local/go/bin:...</string> </dict> </dict> </plist> ``` Load it with: ```bash launchctl load ~/Library/LaunchAgents/com.bioinfo.skills-updater.plist ``` Now every Sunday at 4 AM, the script runs automatically. All updates get logged to `~/logs/skills-updater.log`. ## Running It: First Test Results ``` [2026-01-12 11:19:01] Skills CLI Updater - 2026-01-12 11:19 [2026-01-12 11:19:01] Phase 1: Discovering CLI dependencies from skills... [2026-01-12 11:19:01] Discovered 34 CLI tools across 73 skills [2026-01-12 11:19:01] Homebrew: 21 formulas [2026-01-12 11:19:01] Go: 10 modules [2026-01-12 11:19:01] Node: 3 packages ... [2026-01-12 11:19:18] bird: 0.6.0 -> 0.7.0 (updating...) [2026-01-12 11:19:19] SUCCESS: bird updated ``` Bird went from 0.6.0 to 0.7.0. The new version includes home timeline support, better pagination, and a bunch of bug fixes. All without me having to remember to check. > [!warning] Tap Freshness > Homebrew taps don't always reflect new versions immediately. The script runs `brew update` first, but third-party taps may lag. If you know a new version exists and the script doesn't see it, run `brew tap --repair <tap-name>` manually. ## The Practical Benefits **Reduced debugging time.** When a skill fails, outdated CLI tools are one less thing to check. You know they're current. **Security patches applied automatically.** CLI tools get vulnerability fixes too. Weekly updates mean you're never more than 7 days behind. **New features available immediately.** Bird 0.7.0 added home timeline support. Now the bird skill can use it without manual intervention. **Discoverable dependencies.** The inventory JSON documents exactly what CLI ecosystem your skills depend on. Useful for documentation, auditing, or setting up a new machine. ## Manual Commands ```bash # Run manually ~/scripts/skills-updater.sh # Dry run (see what would update) ~/scripts/skills-updater.sh --dry-run # Check LaunchAgent status launchctl list | grep skills-updater # View last run tail -100 ~/logs/skills-updater.log # View inventory cat ~/scripts/skills-inventory.json | jq ``` ## What's Next This handles the happy path. Future improvements could include: - **Slack/Discord notifications** when updates are applied - **Rollback support** if an update breaks something - **Version constraint parsing** for skills that need specific versions - **Cross-machine sync** for homelab setups with multiple nodes For now, the system does what I need: keeps 34 CLI tools current across 73 skills without me thinking about it. The code is straightforward bash. If you're running Claude Code with skills that depend on CLI tools, adapt it to your setup. The core insight is that skill metadata already contains the dependency information. You just need to parse it. --- ### Related Articles - [[Practical Applications/claude-skills-vs-mcp-servers|Claude Skills vs MCP Servers]] - [[AI Development & Agents/claude-code-best-practices|Claude Code Best Practices]] - [[Practical Applications/debugging-claude-code-with-claude|Debugging Claude Code with Claude]] --- <p style="text-align: center;"><strong>About the Author</strong>: Justin Johnson builds AI systems and writes about practical AI development.</p> <p style="text-align: center;"><a href="https://justinhjohnson.com">justinhjohnson.com</a> | <a href="https://twitter.com/bioinfo">Twitter</a> | <a href="https://www.linkedin.com/in/justinhaywardjohnson/">LinkedIn</a> | <a href="https://rundatarun.io">Run Data Run</a> | <a href="https://subscribe.rundatarun.io">Subscribe</a></p>