From cb19eea77f66feed2100e85c9d51c701fcb46abc Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Fri, 22 May 2026 05:33:18 -0600 Subject: [PATCH] feat: advertise and serve agent skills from .well-known (#44878) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Adds `apps/www/scripts/fetchAgentSkills.mjs` — at build time (`pnpm content:build`) fetches the latest `index.json` from `supabase/agent-skills` release assets and writes it verbatim to `public/.well-known/agent-skills/index.json` - Skill URLs are absolute GitHub Release asset URLs, embedded by the agent-skills repo at release time (supabase/agent-skills#87) — no URL rewriting needed on this side ## How it works 1. Fetches latest release from `supabase/agent-skills` via GitHub API 2. Downloads `index.json` from the release assets 3. Writes it verbatim to `public/.well-known/agent-skills/index.json` Clients discover and install skills from `supabase.com/.well-known/agent-skills/index.json` and fetch tarballs directly from GitHub Release assets. ## Dependency Requires supabase/agent-skills#87 to be merged and released so the published `index.json` contains absolute URLs. --------- Co-authored-by: Pedro Rodrigues <44656907+Rodriguespn@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 (1M context) Co-authored-by: Pedro Rodrigues --- apps/www/package.json | 2 +- apps/www/scripts/fetchAgentSkills.mjs | 49 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 apps/www/scripts/fetchAgentSkills.mjs diff --git a/apps/www/package.json b/apps/www/package.json index 262d7d7992b..7757cc8c82e 100644 --- a/apps/www/package.json +++ b/apps/www/package.json @@ -13,7 +13,7 @@ "clean": "rimraf node_modules", "pretypecheck": "next typegen", "typecheck": "pnpm run content:build && tsc --noEmit", - "content:build": "node scripts/generateStaticContent.mjs && node scripts/generateMdContent.mjs", + "content:build": "node scripts/generateStaticContent.mjs && node scripts/generateMdContent.mjs && node scripts/fetchAgentSkills.mjs", "test": "vitest --run", "test:watch": "vitest watch", "postbuild": "node ./internals/generate-sitemap.mjs && ./../../scripts/upload-static-assets.sh" diff --git a/apps/www/scripts/fetchAgentSkills.mjs b/apps/www/scripts/fetchAgentSkills.mjs new file mode 100644 index 00000000000..36a70cf87f0 --- /dev/null +++ b/apps/www/scripts/fetchAgentSkills.mjs @@ -0,0 +1,49 @@ +// @ts-check + +/** + * Fetches the latest agent-skills index.json from supabase/agent-skills and + * writes it to public/.well-known/agent-skills/index.json. + * + * Skill URLs in the published index.json are absolute GitHub Release asset + * URLs — no rewriting needed on this side. + * + * Spec: https://github.com/agentskills/agentskills/pull/254 + * Runs unauthenticated — public repo, build-time only. + */ + +import { promises as fs } from 'node:fs' +import { dirname, join } from 'node:path' +import { fileURLToPath } from 'node:url' + +const __dirname = dirname(fileURLToPath(import.meta.url)) +const OUT_DIR = join(__dirname, '..', 'public', '.well-known', 'agent-skills') +const REPO = 'supabase/agent-skills' + +async function fetchJson(url) { + const res = await fetch(url, { headers: { 'User-Agent': 'supabase-www-build' } }) + if (!res.ok) throw new Error(`GET ${url} → ${res.status}`) + return res.json() +} + +async function main() { + const release = await fetchJson(`https://api.github.com/repos/${REPO}/releases/latest`) + console.log(`Fetching agent-skills release: ${release.tag_name}`) + + const indexAsset = release.assets.find((a) => a.name === 'index.json') + if (!indexAsset) throw new Error('No index.json found in release assets') + + const index = await fetchJson(indexAsset.browser_download_url) + + await fs.mkdir(OUT_DIR, { recursive: true }) + await fs.writeFile(join(OUT_DIR, 'index.json'), JSON.stringify(index, null, 2) + '\n') + + for (const skill of index.skills ?? []) { + console.log(` ${skill.name}`) + } + console.log(`Done — wrote public/.well-known/agent-skills/index.json`) +} + +main().catch((err) => { + console.error(err) + process.exit(1) +})