Fast-forward the coding-agent-skills clone these skills were deployed from to origin/main, then redeploy every skill: at the latest release on origin/main by default, or at main on the main channel. Stops before a release that raises the major version until the user passes --cross-major, and over a deployment the user pinned with deploy.py --at until the user passes --unpin.
Installs into .claude/skills of the current project.
Are you the author of Update Coding Agent Skills?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/ejryan89-update-coding-agent-skills)
---
name: update-coding-agent-skills
description: "Fast-forward the coding-agent-skills clone these skills were deployed from to origin/main, then redeploy every skill: at the latest release on origin/main by default, or at main on the main channel. Stops before a release that raises the major version until the user passes --cross-major, and over a deployment the user pinned with deploy.py --at until the user passes --unpin."
argument-hint: "[--channel release | main] [--cross-major] [--unpin]"
allowed-tools: ["Bash(bash \"${CLAUDE_SKILL_DIR}/scripts/update.sh\" *)", "PowerShell(bash \"${CLAUDE_SKILL_DIR}/scripts/update.sh\" *)"]
disable-model-invocation: true
---
Update the clone at `{{SOURCE_ROOT}}` and redeploy it. Fixes land on `main` and reach users at the next release tag, so by default the update follows releases: the release channel deploys the highest release tag on `origin/main`, a release marked as a pre-release included, with `deploy.py --at refs/tags/<tag>`, which pins the installation there until a later release. The main channel, which the user opts into with `UPDATE_CHANNEL=main` in the deployer's `configure` command or for one run with `--channel main`, deploys `main` itself. Either way the clone is fast-forwarded to `origin/main` and stays on `main`. Run the update script once, without piping it, through the Bash tool when there is one (in PowerShell, `bash` can be WSL's rather than Git Bash), and report what it printed. Pass after the configured channel each of `--channel <release or main>`, `--cross-major`, and `--unpin` that the user started the skill with, and nothing else.
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/update.sh" "{{SOURCE_ROOT}}" "{{UPDATE_CHANNEL}}"
```
The first line of output is the status; act on it, not on the exit code:
- `UP_TO_DATE <tag>` or `UPDATED <old>..<tag>`, on the release channel: the installation was at, or is moved from the deployed commit `<old>` (`unknown` when `deploy.py check` named none) to, the release `<tag>`. `UPDATED` is followed by the commits the release adds, and by `NOT_IN_RELEASE <tag>..<old>` and the deployed commits the release does not carry, as when the installation had followed `main` past the release; say that those changes leave the installation until a release carries them, or until the user opts into `main`.
- `UP_TO_DATE <sha>` or `UPDATED <old>..<new>`, on the main channel: local `main` was at, or is fast-forwarded to, `origin/main`, and `UPDATED` is followed by the pulled commits.
- After either: `CROSSED <current>..<target>` when `--cross-major` accepted a release boundary, then the deployer's output, ending in `DEPLOYED`, `DEPLOY_FAILED <code>`, or `DEPLOY_PINNED <ref> <commit>`. A clone found on another branch was switched to `main` and stays there. Report the range, the listed commits, the crossing if any, and the deployer's summary of updated, unchanged, skipped, and removed skills. If the deployer printed `Replaced the deployment pinned with --at <ref> ...`, quote that line. On `DEPLOY_FAILED`, quote the deployer's error.
- `DEPLOY_PINNED <ref> <commit>`, last after `UP_TO_DATE` or `UPDATED` on the main channel: the installation was pinned with `deploy.py --at <ref>` at `<commit>`, though `deploy.py check` did not name the pin, and the deployer refused to replace it without `--unpin`. The clone is on `main` at `origin/main`, but nothing was deployed. Report the range, the ref, and the commit, and say that rerunning the skill with `--unpin` deploys `main`, and that until then the installation stays at the pinned commit. Do not rerun it yourself.
- `MAJOR_UPDATE <current>..<target>`: the highest release on `origin/main` raises the major version above the installed one (or the minor version, while the major is 0). The installed version is the release of the commit `deploy.py check` names as deployed; `<current>` is `untagged` when no release tag reaches that commit, which counts as version 0.0.0, and `unknown` when check names no deployed commit, which any release stops. The listed commits are what the update would deploy, up to the release on the release channel. The update may ask the user to act, as the release notes say. Nothing was merged or deployed. Report both versions and the commits, point the user at the release notes for `<target>` on the repository's releases page, and say that rerunning the skill with `--cross-major` applies it. Do not rerun it yourself.
- `PINNED <ref> <commit>`: the user pinned the installation with `deploy.py --at <ref>` at `<commit>`, and the update would replace it: on the main channel with `main`, before anything was fetched, and on the release channel with a release at another commit, after the fetch. Nothing was merged or deployed. Report the ref and the commit, and say that rerunning the skill with `--unpin` updates past the pin, and that until then the installation stays at the pinned commit. Do not rerun it yourself.
- `NO_RELEASE`, on the release channel: no release tag reaches `origin/main`, so there is no release to deploy. The clone was fetched; nothing was merged or deployed. Report it, say that `--channel main` deploys `main` for one run, and stop.
- `DIRTY`: tracked files have uncommitted changes, listed below it. Nothing was fetched. Report the files and stop.
- `TAG_SHADOWS_BRANCH`: a tag named `main` or `origin/main`, listed below it as `on origin` or `in the clone`, would stand in for that branch. Nothing was fetched, merged, or deployed. Report the tags and stop; removing one is the user's decision.
- `FETCH_FAILED`, `CHECKOUT_FAILED`, or `NOT_FAST_FORWARD`: nothing was merged or deployed, and the clone is on the branch it was found on. Report what follows the status and stop. `NOT_FAST_FORWARD` lists the commits local `main` has that `origin/main` lacks, or quotes Git's refusal; a `still on main:` line below it means the clone could not be switched back, so report that too.
- `FAILED <reason>`: the clone path holds no `deploy.py` or is not a Git repository, a step failed outright, or a release tag has a version number too long to compare. Nothing was merged or deployed. Report the reason and stop.
- A usage error (exit 2) prints only on stderr: report it and stop.
Never stash, rebase, reset, or force anything to work around a stop, and never rerun the deployer with `--force` or `--force-item`; those decisions are the user's.