How Download Links for Skill Artifacts Are Managed in the garden-skills README
The garden-skills repository uses HTML comment markers in the README that are automatically replaced with live download links by the update-readme.mjs script, ensuring users always access the latest released artifact from GitHub Releases.
The ConardLi/garden-skills project distributes skill packages as zipped artifacts attached to GitHub Releases. To keep documentation synchronized with actual releases, the repository implements an automated system that generates download links for skill artifacts directly within the README using placeholder markers and a Node.js release script.
Marker-Based Download Links in the README
Rather than hard-coding static URLs that quickly become stale, the README contains HTML comment markers that delimit where dynamic download links should appear. These markers follow the pattern <!-- DOWNLOAD:<skill-id>:start --> and <!-- DOWNLOAD:<skill-id>:end -->.
For example, the web-design-engineer skill embeds its link like this:
<!-- DOWNLOAD:web-design-engineer:start -->[Download v1.3.0 .zip](https://github.com/ConardLi/garden-skills/releases/download/web-design-engineer-v1.3.0/web-design-engineer-1.3.0.zip)<!-- DOWNLOAD:web-design-engineer:end -->
This approach allows the automation script to perform targeted text replacements without affecting surrounding documentation content.
The Automation Pipeline
The core logic resides in scripts/release/update-readme.mjs. This script orchestrates the link generation process by querying Git tags and rebuilding markdown links for every skill defined in the repository.
Loading Skill Manifests
The script initializes by calling loadAllManifests from scripts/release/lib/skills.mjs. This function enumerates all skill directories and loads their configuration files, establishing the complete catalog of artifacts that require download links for skill artifacts in the README.
Resolving Latest Versions from Git Tags
Critically, the system determines the current release version by parsing Git tags rather than reading manifest.json files. This prevents 404 errors when developers bump manifest versions before cutting an actual release.
The lastTagFor function uses parseTag, which applies the following regex to identify valid release tags:
const TAG_RE = /^([a-z0-9][a-z0-9-]*[a-z0-9])-v(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)$/;
export function parseTag(tag) {
const m = TAG_RE.exec(tag);
if (!m) return null;
return { skill: m[1], version: m[2] };
}
This regex expects tags formatted as <skill>-v<semver> (e.g., gpt-image-2-v1.0.4). By scanning the repository's tag history, the script identifies the most recent valid release for each skill, ensuring the README always links to existing assets.
Constructing Download URLs
For each skill with a published release, the buildBlock function generates the final markdown link:
function buildBlock(skill, version, repo, lang) {
if (!version) return COPY[lang].unreleased;
const tag = buildTag(skill, version); // `<skill>-v<version>`
const zip = zipName(skill, version); // `<skill>-<version>.zip`
const url = `https://github.com/${repo}/releases/download/${tag}/${zip}`;
const label = COPY[lang].label.replace("%V", version);
return `[${label}](${url})`;
}
The function assembles the GitHub Releases URL using:
- Tag name: Constructed by
buildTag(e.g.,web-design-engineer-v1.3.0) - Filename: Generated by
zipNamefollowing the pattern${skill}-${version}.zip - Repository: The target GitHub repository identifier (e.g.,
ConardLi/garden-skills)
Idempotent README Updates
The script performs a rewrite pass over README.md and localized variants, replacing content between each <!-- DOWNLOAD:...:start --> and <!-- DOWNLOAD:...:end --> marker with the freshly generated buildBlock output. This operation is idempotent—running the script multiple times produces identical results when no new releases exist, making it safe to execute during every CI pipeline.
Release Workflow Integration
The update process typically executes during CI/CD pipelines immediately after a new tag is pushed. When a maintainer releases version 1.3.0 of the web-design-engineer skill:
- The Git tag
web-design-engineer-v1.3.0is created and the ZIP artifact uploads to GitHub Releases update-readme.mjsqueries tags vialastTagForand detects the new versionbuildBlockgenerates the updated markdown URL pointing to the specific release asset- The script rewrites the marker block in
README.mdwith the new link - Changes are committed back to the repository
This workflow ensures that visitors browsing the repository always see functional download links for skill artifacts pointing to existing, downloadable release assets.
Summary
- The README uses HTML comment markers (
<!-- DOWNLOAD:skill:start -->and<!-- DOWNLOAD:skill:end -->) to define dynamic link regions that the script can safely rewrite - The
scripts/release/update-readme.mjsscript automates link generation during releases by querying the Git tag history - Version resolution relies on Git tags matching the
<skill>-v<semver>pattern viaparseTag, not the version field in manifest files - The
buildBlockfunction constructs GitHub Releases URLs following the templatehttps://github.com/${repo}/releases/download/${tag}/${zip} - The rewrite process is idempotent and supports multiple languages through the
COPYconfiguration object passed tobuildBlock
Frequently Asked Questions
Why does the script use Git tags instead of manifest.json for versioning?
Reading version information from Git tags ensures that the README only advertises releases that actually exist on GitHub. If the script read from manifest.json, it might generate links to artifacts that have not been built or uploaded yet, resulting in 404 errors for users attempting to download skill artifacts.
What happens if a skill has no releases yet?
When lastTagFor returns null for a skill, the buildBlock function returns an "unreleased" placeholder string defined in the COPY localization object. This indicates that the skill is available in the repository source but has not yet been packaged into a downloadable ZIP file.
Can the script handle localized README files?
Yes. The update-readme.mjs script processes multiple README variants (e.g., README.zh-CN.md), using the lang parameter in buildBlock to select appropriate label text for different languages from the COPY configuration object.
Is the regex pattern for tags configurable?
The TAG_RE constant in scripts/release/lib/skills.mjs is hardcoded to enforce the convention of lowercase alphanumeric skill names with hyphens followed by semantic versioning (e.g., skill-name-v1.2.3). Modifying this regex would require editing the source code in skills.mjs to support alternative tagging conventions.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →