Repository navigation
Check that each skill is up to date on first use - #26
Conversation
Each SKILL.md now has a short "check this skill is current" section under its H1. The agent fetches the docs site's skills index once per conversation and compares the published version with the installed one. It mentions an update only when the index has a newer version, and never runs it itself. The request carries analytics query parameters (skill, version, surface, model, purpose, and the cloud name if the agent already has it from the conversation or code). - templates/version-check.md is the single source for the block - scripts/check-version-block.sh renders it into each skill (--fix) or checks it - New CI job fails on a missing, edited, or misplaced block - README discloses what's sent and how to turn the check off - CONTRIBUTING covers editing the block and rerunning --fix after a version bump - Minor version bump for all four skills
skills@latest (1.7.4) requires Node 22.20 or newer and crashes on Node 20.
jackieros
left a comment
There was a problem hiding this comment.
Some suggestions/questions - both mine from my personal review & some that claude raised.
| - `<surface>`: the product you're running in, lowercase with hyphens, for example `claude-code`, `cursor`, `codex`, `copilot`, `claude-desktop`, or `chatgpt`. | ||
| - `<model>`: your model ID if you know it, otherwise `unknown`. | ||
| - `<purpose>`: one of `setup`, `upload`, `transform`, `debug`, or `docs`. | ||
| - `<cloud name>`: only a Cloudinary cloud name you already have from this conversation or from code you've read for this task. Don't open `.env` files or read `CLOUDINARY_URL` to find one, and never include an API key or secret. If you don't have one, drop `&cloud_name=<cloud name>` from the URL. |
There was a problem hiding this comment.
I think the chances of a cloud name being discussed in a conversation except when a user is first configuring their account is close to 0. If they implemented their cld config properly, same is true for seeing a cloud name directly in code they've read for this task, since cloud usually wont be in the code anywhere except the .env file (or whatever file they use to configure the SDK). That means that I'd expect we'd almost never get account details from this check, which was the primary goal.
Slightly expanded suggestion below that hopefully increases the chances of getting a cloud name while keeping the privacy story stays pretty much the same. Open to improvements.
There was a problem hiding this comment.
Good point, agreed that "mentioned in chat" alone would almost never give us a cloud name. I took your suggestion and tweaked slightly, including the unknown addition. Still avoided doing any .env check as I think it's a security concern.
Co-authored-by: Jackie Rosenzveig <jackie@cloudinary.com>
…ng the correct one.
|
Hi @njb90 @jackieros, just an FYI: this PR is currently a blocker for #28 (the next-cloudinary v7 updates to the cloudinary-next skill). The "Every SKILL.md is discovered" check is failing on PRs based on main, because npx skills@latest now needs Node 22.20 or later and the workflow on main still uses Node 20. This PR includes the Node 22 workflow change (57f413b), so #28 will be waiting for this one to be merged. Once this is merged, I'll update #28 from main and bump cloudinary-next to 1.2.0, since both PRs currently bump it to 1.1.0. Nothing extra is needed on this PR for that. Thank you! |
|
Note on the While confirming that this branch passes it, I found two gaps. Both are tracked for a separate PR in DOC-11784. 1. The check doesn't require a higher versionThe check compares the PR's base and head commits and fails only when a changed skill's if [ "$bv" = "$hv" ]; then # failIt never checks that the new version is higher. A branch that lowers a version (for example This PR is fine: all four skills it touches move ahead of Suggested fix (separate PR): replace the equality test with a semver comparison, so the check fails unless head > base. For example: if [ "$(printf '%s\n%s\n' "$bv" "$hv" | sort -V | tail -1)" != "$hv" ] || [ "$bv" = "$hv" ]; then
echo "::error file=$head_md,line=7::$name changed but metadata.version ($hv) is not higher than $bv. Bump it (see CONTRIBUTING.md, Versioning)."
fail=12. The wording reads as "bump on every commit"The check compares the whole branch with production, so a skill needs one bump per branch, not one per commit. The wording around it doesn't say so, and an agent working on this branch bumped versions again for a later commit, even though they were already ahead of
Suggested fix (same separate PR):
🤖 Generated with Claude Code |
This is a Claude-recommended update to the descriptions of non-framework-specific SDKs to ensure skills get used even when the agent thinks it already knows the required Cloudinary implementation. Prior to this change, skills weren't used at all in two Cld projects when I asked developer-like questions that didn't specifically ask it to use docs/transformations. After adding, the skills were used & the version check worked as expected.
…conjunction when relevant. Without these changes, the agent skipped using important Cloudinary capabilities that weren't directly covered by the react/next-specific patterns.
There was a problem hiding this comment.
@njb90 - Approving with some notes -
-
Tested on 3 projects (cloned from various cloudinary-dev demo projects) using the skills from this branch - Node, Python, and React. In each, I gave it the identical request to add a feature to the project (a new gallery HTML page) - request used simple terminology - "...display them on the page as squares with rounded corners", etc & didn't specifically mention Cloudinary or skills. Each test was in a fresh Claude session.
-
For each test, only after it implemented my request and I validated its implementation generally worked, I asked if it used any skills. In my first test, it didn't use the skills at all because it felt confident it didn't need help.
- Updating the skill descriptions (for the non-framework ones) with the info that had previously been inside the skill under 'Use when...' + adding the TRIGGER guidance resulted in it consistently using the skill in 3 subsequent tests in different sessions with the same initial request wording. The suggestion from Claude was not to use the strong TRIGGER terminology on the framework skills because it expected that framework skills will always be used when the project framework matches and it didn't want to over-push the framework skill.
- On the other hand, when I got to the React test & my first round didn't produce the transformation best practices I expected, it did suggest that within the framework skills to point out that it should also use other cloudinary-xxx skills if the framework one didn't cover all the details it needed. A fresh test on a clean version of that project with the updated react skill gave a better result.
- Please see both of my commits on those and confirm you are good with them (or modify as you see fit)
-
For all the other tests, when I asked if it used skills, just asking that question caused it to not only confirm, but also let me know that it checked the version as instructed & in all our cases, it validated that our version number was higher than the json, and thus didn't need an update.
-
I then asked for the URL it used to check the version & in all cases it gave all the expected query params. In only one of the 3 cases did it pass the cloud name
- Passed the cloud name when it was in a .config file (not .env) and had been modified in the same session - I had added my cloud name - but not yet committed before submitting my implementation request to Claude - so the agent discovered it while checking the status of the branch and the overall project setup.
- In Python it was in .env, which had been updated & saved prior to opening the Claude session - It later (on its own) tested the HTML page that it created & thus had access to URLs, but that was after doing the version check.
- In React, the cloud-name was directly in the app.JS file that the agent edited for the task, but when I asked it said that it did the version check before examining the project files, so it didn't get it.
For now, as you said, we can release this and check what % of the URLs come back with a cloud name and then look to improve, so I'm fine with that for now.
One question before we release this --
The format of URLs passed when checking the skill comes out something like this:
https://cloudinary.com/documentation/.well-known/agent-skills/index.json?install_source=skillspack&referrer=trans-skill&skill=cloudinary-transformations&skill_version=1.1.0&surface=claude-code&model=claude-opus-5-5&source=skill.cloudinary-transformations.deliver&cloud_name=jackie
It quotes which skill it is 3x (once as trans-skill matching what we use for all URL links) and TWO more times as cloudinary-transformations (once as skill=cloudinary-xxx, and once as source=skill.cloudinary-xxx... Feels like overkill - Is there anything we should adjust there, or do you think we should keep it like this?
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary
Most people install skills once and never update them. With this change, each skill checks whether it's up to date the first time it's used in a conversation, and tells the user when a newer version is available.
How it works
Each
SKILL.mdgets a short "Before you start: check this skill is current" section directly under its H1. The first time the skill is used in a conversation, the agent:https://cloudinary.com/documentation/.well-known/agent-skills/index.json. This is the Agent Skills discovery index, which theskillsCLI can also install from.x-cloudinary-versionfor the skill with the installed version.npx skills update <name>, or reinstall withnpx skills add https://cloudinary.com/documentation. Otherwise it carries on.Things it doesn't do:
Agents that can't fetch URLs skip the check. The check also follows the user's or project's instructions to skip it.
What's sent
The request includes the skill name and version, the agent product and model, the kind of task (for example
setupordocs), and the user's cloud name, but only if the agent already has it from the conversation or the code it's working on. The block tells the agent never to open.envfiles or readCLOUDINARY_URLfor this, and never to include API keys or secrets. The README documents this and how to turn the check off.Keeping the block consistent
templates/version-check.mdis the single source for the block.scripts/check-version-block.sh --fixrenders it into every skill, filling in the skill's name, version, and referrer.version-check-block, fails if a skill's block is missing, edited by hand, misplaced, or out of date after a version bump.Versions
Testing
Headless Claude Code runs, with the skills installed from this branch:
To test locally:
Then ask your agent a Cloudinary task. To see the update notice, change the version in an installed skill's
SKILL.mdto0.9.0(in both the frontmatter and the block) and start a new conversation.