Update the vendored marketing skills under claude/skills/ from an aged upstream release. Use when Josh asks to check or update them — 'check the marketing skills for updates,' 'update the coreyhaines skills,' 'are the marketing skills current,' 'pull the latest marketing skills.' Takes only tagged releases at least 7 days old; never automates the pull, never trusts the default branch.
72
88%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
The marketing skills under claude/skills/ are pristine vendored copies from coreyhaines31/marketingskills. This skill refreshes them from upstream — deliberately, and only from aged GitHub releases.
Marketplaces and auto-update mechanisms are prompt-injection vectors: automatically fetching and trusting third-party skill content is how you get injected. So this skill never automates the pull. Trust comes from a tagged release having aged in public for at least 7 days, not from inspecting diffs. Someone else finds the poison first.
The 7-day floor is the whole safety model. Don't shorten it, don't skip it, don't substitute a diff review for it.
Compute the cutoff at runtime — never hardcode a date. Select the newest non-draft, non-prerelease release whose published_at is at or before 7 days ago. No account override is needed — coreyhaines31/marketingskills is public and this only reads release data:
CUTOFF=$(date -u -v-7d +%Y-%m-%dT%H:%M:%SZ)
TAG=$(gh api repos/coreyhaines31/marketingskills/releases --jq \
"[.[] | select(.draft==false and .prerelease==false) | select(.published_at <= \"$CUTOFF\")] | sort_by(.published_at) | reverse | .[0].tag_name")If the newest release is younger than 7 days, this expression already falls back to the newest one that is aged past the cutoff. If TAG comes back empty or null, report "nothing aged past 7 days yet" and stop.
Shallow-clone the repo at that tag into a temp dir. Releases only — never the default branch tip:
TMP=$(mktemp -d)
git clone --depth 1 --branch "$TAG" https://github.com/coreyhaines31/marketingskills "$TMP"Discover the layout — don't hardcode it. Each SKILL.md's parent dir is a skill; the dir name is the skill name:
find "$TMP" -name SKILL.md(At the time of writing, upstream lays these out as skills/<name>/SKILL.md, but discover it each run rather than assuming.)
For each skill present in BOTH the snapshot and local claude/skills/, read metadata.version from each SKILL.md frontmatter and compare as semver. Extract the version from the first frontmatter block:
ver() { # ver <path-to-SKILL.md>
awk '/^---$/{n++; next} n==1 && /^ version:/{gsub(/^ version:[ ]*/,""); print; exit}' "$1"
}Compare with sort -V (version-aware, so 2.0.0 < 2.10.0, not lexical):
if [ "$UP" = "$LOCAL" ]; then
: # equal → skip
else
newest=$(printf '%s\n%s\n' "$UP" "$LOCAL" | sort -V | tail -1)
[ "$newest" = "$UP" ] && echo "update" # upstream strictly newer
fiShow a summary of what bumped, one line each: cro 2.0.0 → 2.1.0. Equal or older upstream → skip.
For each skill whose version bumped, remove the local dir and copy the snapshot's dir in its place. No content diff, no payload inspection — the aged release is trusted.
Two safety points: the copy source is the parent dir find located for that skill in Step 3 (SRC), never a re-derived $TMP/skills/<name>; the copy target is anchored under $DOTFILES (the repo root), never a relative path — a relative rm -rf fires against the wrong tree if the CWD isn't the repo root.
# SRC = the SKILL.md parent dir that `find` returned for this skill in step 3
name=$(basename "$SRC")
DEST="$DOTFILES/claude/skills/$name"
rm -rf "$DEST"
cp -R "$SRC" "$DEST"Only skills whose version actually bumped get touched.
Collect skills present in the snapshot but NOT in local $DOTFILES/claude/skills/, and present them to Josh as a short list, asking which to add. Default toward yes, but he chooses — don't dump all of them in silently. Add only the ones he picks — copy each with the same anchored pattern as Step 5 (cp -R "$SRC" "$DOTFILES/claude/skills/$name").
Skills Josh vendors that upstream no longer has: leave them alone, just note them in the summary.
Delete the temp snapshot, then commit everything this run changed — the updated skill dirs from Step 5 plus any skills Josh chose to add in Step 6 — in a SINGLE commit. Stage under $DOTFILES (never a relative path, same anchoring as Step 5) so the commit runs from the repo root regardless of CWD.
rm -rf "$TMP"
cd "$DOTFILES"
git add "$DOTFILES/claude/skills"
git commit -m "update marketing skills to $TAG" -m "cro 2.0.0 → 2.1.0
launch 1.4.0 → 1.5.0
+ prospecting 2.1.0 (added)
Co-Authored-By: Dunnbot <dunnbot@joshmanders.com>"The subject names the release tag pulled this run (fill the real $TAG, e.g. update marketing skills to v2.10.0). The body carries one line per changed skill: a bump line cro 2.0.0 → 2.1.0 for each updated skill from Step 5, and a + <name> <version> (added) line for each skill added in Step 6. Match the repo's commit conventions and keep the Co-Authored-By: Dunnbot <dunnbot@joshmanders.com> attribution trailer the other commits use. Don't walk the implementation in the message.
COMMIT ONLY — never push. Pushing stays Josh's separate call.
Then report the per-skill summary and the resulting commit SHA.
npx skills-style).54ab5f6
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.