ci-watcher — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited ci-watcher (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
CI watcher: always-on background process that monitors CI and notifies on both failure and pass via webhook channel. Launch once per feature — the watcher never exits, so no re-launch is needed.
THE CI WATCHER MUST NEVER BE KILLED BY CLAUDE ON ITS OWN. This is an absolute rule with no exceptions:
main./ci-watcher stop, touch /tmp/ci_watch_kill_*, kill <pid>, pkill ci_watch, or any equivalent on your own initiative.The watcher is intentionally always-on and stays alive across CI runs, PR merges, branch switches, and feature transitions.
THE ONLY WAY TO STOP THE WATCHER IS AN EXPLICIT USER REQUEST, such as the user typing /ci-watcher stop or giving a clear natural-language instruction like "stop the ci watcher" / "kill the ci watcher". If the user has not explicitly asked, leave it running.
stop subcommandIf the first argument is stop, drop a per-session kill flag and exit — do NOT launch the watcher:
if [[ -z "${CLAUDE_CODE_SESSION_ID:-}" ]]; then
echo "Error: CLAUDE_CODE_SESSION_ID is unset; cannot stop ci watcher." >&2
exit 1
fi
touch "/tmp/ci_watch_kill_${CLAUDE_CODE_SESSION_ID}"
echo "CI watcher stop flag set for session ${CLAUDE_CODE_SESSION_ID}"The running watcher (if any) will detect the flag at its next poll iteration and exit cleanly.
"$ARGUMENTS"
If user input is provided- determine branch name from it. If not, determine the current branch:
git branch --show-currentCall the get_port MCP tool (from the webhook server). It returns PORT:TOKEN format. Parse the result: everything before the first : is $PORT, everything after is $SESSION_TOKEN.
The watcher sends notifications via curl to the webhook HTTP server on the port obtained above.
Launch with shell-level backgrounding (do NOT use run_in_background=true — the process dies when the subagent exits):
if [[ -z "${CLAUDE_CODE_SESSION_ID:-}" ]]; then
echo "Error: CLAUDE_CODE_SESSION_ID is unset; cannot launch ci watcher." >&2
exit 1
fi
uv run ~/.claude/scripts/ci_watch.py "$BRANCH" "$PORT" "$SESSION_TOKEN" \
</dev/null >>/tmp/ci_watch_${CLAUDE_CODE_SESSION_ID}.log 2>&1 &
echo "CI watcher launched for branch $BRANCH (PID $!, log: /tmp/ci_watch_${CLAUDE_CODE_SESSION_ID}.log)"Note: state, PR-cache, lock, and log files in /tmp/ are all keyed on CLAUDE_CODE_SESSION_ID (full UUID). The watched branch is recorded inside the state file as <branch>:<state>. Switching branches mid-feature re-launches /ci-watcher, which kills the old watcher via its PID lock and starts a new one with the new branch.
The watcher will frequently surface "CI behind" / "branch behind" problems, and that means we will repeatedly need to sync. This is intentional, not a bug. Do NOT ignore any "CI behind" / branch-behind alert, and do NOT escalate it to the user. Just keep fixing and re-syncing every single time it comes up — however many times that is.
After a PR is merged, do NOT kill the watcher (see the CRITICAL RULE above). It keeps watching the CI run triggered by the merge to main and will alert us if that post-merge run fails. If the post-merge main CI fails, fix it in a separate/new PR — never reopen or reuse the merged one.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.