# Tool Pin Drift

> Check pinned external tool versions against npm and GitHub releases. Use for the weekly heartbeat tool-pin drift scan.

- Skill: `jasoncarreira/tool-pin-drift` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds add jasoncarreira/tool-pin-drift`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jasoncarreira/tool-pin-drift/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: jasoncarreira (https://skillmd.com/u/jasoncarreira)
- Updated: 2026-08-19
- Page: https://skillmd.com/skills/jasoncarreira/tool-pin-drift

---


<!-- desc: Run the immutable, data-driven npm and GitHub tool-pin drift checker and consume its per-target JSON results. -->

# Tool Pin Drift

Checks the source-controlled targets in `scripts/targets.json` and emits one JSON
document. Each target reports `pinned_version`, `latest_version`, `drifted`,
`status`, and `error`; one failed lookup does not prevent the remaining targets
from running.

## Invocation

The deployment declares and invokes exactly this command, with no arguments,
shell operators, pipes, or redirection:

```bash
python3 /mimir-home/.mimir_builtin_skills/tool-pin-drift/scripts/check_tool_pins.py
```

The corresponding `scheduler.yaml` declaration is:

```yaml
shell_commands:
  - exec: python3
    path: /usr/local/bin/python3
    script: /mimir-home/.mimir_builtin_skills/tool-pin-drift/scripts/check_tool_pins.py
```

The declared `path` is deployment-specific and must name the Python interpreter
that deployment actually runs. The mimirbot and muninn containers currently use
`/usr/local/bin/python3`; a different or incorrect path is refused rather than
falling back to another interpreter.

The script intentionally runs `npm` and `gh` as ordinary subprocesses. Those
commands must not be added to the shared `maintenance` shell profile. Declaring
this immutable builtin script grants its subprocess behavior only to the job
whose operator-owned scheduler entry names it.

## Output

`status` is `drift`, `no_drift`, or `error`. On an error, `latest_version` and
`drifted` are `null`, and `error` contains the per-target failure. The process
still checks every other target and exits successfully after emitting the full
result.

