From e92c124b0fc9fbf8a826fad059b14f3bb6c94c33 Mon Sep 17 00:00:00 2001 From: allexp1 Date: Fri, 30 Oct 2026 16:48:54 +0200 Subject: [PATCH 1/2] Add Agent Skills discovery index (.well-known/agent-skills) with builder, CI check and website mirror Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01EkqDrNJyC24ZuqGd3731Ay --- .well-known/agent-skills/didww-connect.tar.gz | Bin 0 -> 9220 bytes .../agent-skills/didww-to-elevenlabs.tar.gz | Bin 0 -> 5226 bytes .../agent-skills/didww-to-livekit.tar.gz | Bin 0 -> 9692 bytes .../didww-to-openai-realtime.tar.gz | Bin 0 -> 6679 bytes .../agent-skills/didww-to-retell.tar.gz | Bin 0 -> 4433 bytes .../agent-skills/didww-to-ultravox.tar.gz | Bin 0 -> 5692 bytes .well-known/agent-skills/didww-to-vapi.tar.gz | Bin 0 -> 6349 bytes .../agent-skills/didww-to-vogent.tar.gz | Bin 0 -> 3814 bytes .well-known/agent-skills/didww-to-xai.tar.gz | Bin 0 -> 4365 bytes .well-known/agent-skills/index.json | 99 ++++++++++++ CHANGELOG.md | 6 + CONTRIBUTING.md | 4 +- README.md | 4 + docs/agent-skills-index.md | 53 +++++++ scripts/build_index.py | 145 ++++++++++++++++++ scripts/mirror_index.py | 89 +++++++++++ scripts/test.sh | 1 + scripts/test_index.py | 89 +++++++++++ 18 files changed, 489 insertions(+), 1 deletion(-) create mode 100644 .well-known/agent-skills/didww-connect.tar.gz create mode 100644 .well-known/agent-skills/didww-to-elevenlabs.tar.gz create mode 100644 .well-known/agent-skills/didww-to-livekit.tar.gz create mode 100644 .well-known/agent-skills/didww-to-openai-realtime.tar.gz create mode 100644 .well-known/agent-skills/didww-to-retell.tar.gz create mode 100644 .well-known/agent-skills/didww-to-ultravox.tar.gz create mode 100644 .well-known/agent-skills/didww-to-vapi.tar.gz create mode 100644 .well-known/agent-skills/didww-to-vogent.tar.gz create mode 100644 .well-known/agent-skills/didww-to-xai.tar.gz create mode 100644 .well-known/agent-skills/index.json create mode 100644 docs/agent-skills-index.md create mode 100644 scripts/build_index.py create mode 100644 scripts/mirror_index.py create mode 100644 scripts/test_index.py diff --git a/.well-known/agent-skills/didww-connect.tar.gz b/.well-known/agent-skills/didww-connect.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..6ce99f4bb43122947512bd91bbe626b760e1c6c7 GIT binary patch literal 9220 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 a)Ae*cT~F83^>qDDy8aj5QqF7ucmMz!O!Zv= literal 0 HcmV?d00001 diff --git a/.well-known/agent-skills/didww-to-elevenlabs.tar.gz b/.well-known/agent-skills/didww-to-elevenlabs.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..e466a4af362d12ca60b11e8398dd6c0313f8cd94 GIT binary patch literal 5226 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 literal 0 HcmV?d00001 diff --git a/.well-known/agent-skills/didww-to-livekit.tar.gz b/.well-known/agent-skills/didww-to-livekit.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..3f7bfbcc61c71e67dfc42de41bf0bd5d7e29774a GIT binary patch literal 9692 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 literal 0 HcmV?d00001 diff --git a/.well-known/agent-skills/didww-to-openai-realtime.tar.gz b/.well-known/agent-skills/didww-to-openai-realtime.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..029eef0ddd66eafdec962136aaf64a9b767f5452 GIT binary patch literal 6679 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 literal 0 HcmV?d00001 diff --git a/.well-known/agent-skills/didww-to-retell.tar.gz b/.well-known/agent-skills/didww-to-retell.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..6f2adf1672e37fc985cdac79f93d0bcef0e7a044 GIT binary patch literal 4433 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 literal 0 HcmV?d00001 diff --git a/.well-known/agent-skills/didww-to-vapi.tar.gz b/.well-known/agent-skills/didww-to-vapi.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..df46726a91bb510279cb8f5236b06599fe9abaa0 GIT binary patch literal 6349 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 literal 0 HcmV?d00001 diff --git a/.well-known/agent-skills/didww-to-vogent.tar.gz b/.well-known/agent-skills/didww-to-vogent.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..790f557b04378ffffdbb0b76e21c32ce241d9159 GIT binary patch literal 3814 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 H08jt`&ogp5 literal 0 HcmV?d00001 diff --git a/.well-known/agent-skills/index.json b/.well-known/agent-skills/index.json new file mode 100644 index 0000000..31b44f1 --- /dev/null +++ b/.well-known/agent-skills/index.json @@ -0,0 +1,99 @@ +{ + "$schema": "https://schemas.agentskills.io/discovery/0.2.0/schema.json", + "name": "DIDWW Agent Skills", + "description": "Official DIDWW agent skills: put an AI voice agent on a real DIDWW phone number with any major voice AI platform, through the DIDWW MCP (https://api.didww.com/mcp).", + "repository": "https://github.com/didww/ai", + "homepage": "https://www.didww.com/", + "skills": [ + { + "name": "didww-connect", + "type": "archive", + "description": "Connect a DIDWW phone number to ANY AI voice platform: helps choose the platform, then wires the SIP trunk pair and number. Use whenever the user wants a voice AI agent on a DIDWW number and has not committed to a platform, asks which AI platform to use with DIDWW, or names a platform that has no dedicated didww-to-X skill installed. Covers ElevenLabs, Vapi, Retell, Ultravox, Vogent, OpenAI Realtime, xAI, LiveKit and the enterprise-gated platforms.", + "url": "didww-connect.tar.gz", + "digest": "sha256:50a913c53d738eeb409f565143d176998a04edd8008dcbdbf0777a056a52a9f5", + "version": "1.0.2", + "documentation": "https://github.com/didww/ai/blob/main/docs/didww-connect.md", + "install": "npx didww-connect" + }, + { + "name": "didww-to-elevenlabs", + "type": "archive", + "description": "Connect a DIDWW phone number to an ElevenLabs voice agent over SIP, as automatically as both platforms allow. Use whenever the user wants an ElevenLabs agent (Agents Platform, Conversational AI) on a real phone number via DIDWW, mentions pairing DIDWW with ElevenLabs, importing a SIP trunk into ElevenLabs, sip.rtc.elevenlabs.io, or debugging calls between the two. Covers inbound, outbound, transfers and verification.", + "url": "didww-to-elevenlabs.tar.gz", + "digest": "sha256:522f41eada5f5e6269f9ea71de7452d13e57d077d11643abb6b222fc50bc1e9c", + "version": "1.1.0", + "documentation": "https://github.com/didww/ai/blob/main/docs/didww-to-elevenlabs.md", + "install": "npx didww-to-elevenlabs" + }, + { + "name": "didww-to-livekit", + "type": "archive", + "description": "Connect a DIDWW phone number to a LiveKit Agents worker over SIP, on LiveKit Cloud or self-hosted: inbound trunk, dispatch rule to a named agent, optional outbound trunk. Use whenever the user wants a LiveKit agent (any STT, LLM and TTS combination, including Claude as the brain) answering a real number via DIDWW, mentions sip.livekit.cloud, SIP inbound trunks or dispatch rules, lk sip commands, agent_name dispatch, or debugging calls between DIDWW and LiveKit. This is the bring-your-own-brain pairing: the agent is code the user runs.", + "url": "didww-to-livekit.tar.gz", + "digest": "sha256:b080e937be6335de5dab427e74584f15d8621445e6bc7969a8b5b24607b2aa62", + "version": "1.1.1", + "documentation": "https://github.com/didww/ai/blob/main/docs/didww-to-livekit.md", + "install": "npx didww-to-livekit" + }, + { + "name": "didww-to-openai-realtime", + "type": "archive", + "description": "Point a DIDWW phone number directly at OpenAI's Realtime API over SIP, with a generated webhook backend for call control. Use whenever the user wants gpt-realtime answering a real phone number via DIDWW, mentions sip.api.openai.com, realtime.call.incoming webhooks, Realtime SIP, or debugging calls between DIDWW and OpenAI. This is the developer-grade pairing: the agent behavior is code the user owns.", + "url": "didww-to-openai-realtime.tar.gz", + "digest": "sha256:78f33de78d5aa29d849480e4df51c43802d738350a1d0403be725c808a190c25", + "version": "1.1.0", + "documentation": "https://github.com/didww/ai/blob/main/docs/didww-to-openai-realtime.md", + "install": "npx didww-to-openai-realtime" + }, + { + "name": "didww-to-retell", + "type": "archive", + "description": "Connect a DIDWW phone number to a Retell AI agent over custom telephony, with full MCP automation: Retell's official MCP can create agents AND import numbers. Use whenever the user wants a Retell agent on a real phone number via DIDWW, mentions pairing DIDWW with Retell, custom telephony, sip.retellai.com, import-phone-number, or debugging calls between the two.", + "url": "didww-to-retell.tar.gz", + "digest": "sha256:fe40bae473df088d22c28343df1fab04b86d1b96a250a922cf7e5aa93e82c1b0", + "version": "1.0.2", + "documentation": "https://github.com/didww/ai/blob/main/docs/didww-to-retell.md", + "install": "npx didww-to-retell" + }, + { + "name": "didww-to-ultravox", + "type": "archive", + "description": "Connect a DIDWW phone number to an Ultravox Realtime voice agent over SIP. Use whenever the user wants an Ultravox agent on a real phone number via DIDWW, mentions pairing DIDWW with Ultravox, an account SIP domain, agent_ addresses, allowedCidrRanges, or debugging calls between the two. Covers the address-based routing model that makes Ultravox different from every number-import platform.", + "url": "didww-to-ultravox.tar.gz", + "digest": "sha256:fbf193be6f46d53965c42f9f086c8b6752885e7cb9497b3708df5bca6ed412e5", + "version": "1.1.0", + "documentation": "https://github.com/didww/ai/blob/main/docs/didww-to-ultravox.md", + "install": "npx didww-to-ultravox" + }, + { + "name": "didww-to-vapi", + "type": "archive", + "description": "Connect a DIDWW phone number to a Vapi assistant over BYO SIP trunking, as automatically as Vapi allows. Use whenever the user wants a Vapi assistant on a real phone number via DIDWW, mentions pairing DIDWW with Vapi, byo-sip-trunk credentials, sip.vapi.ai, or debugging calls between the two. Covers inbound, outbound, transfers and agent binding, following Vapi's and DIDWW's own DIDWW guides.", + "url": "didww-to-vapi.tar.gz", + "digest": "sha256:d624bbb9ffa4f3ad69488a779c42ed85a06964c03539a41763556746581cc582", + "version": "1.1.0", + "documentation": "https://github.com/didww/ai/blob/main/docs/didww-to-vapi.md", + "install": "npx didww-to-vapi" + }, + { + "name": "didww-to-vogent", + "type": "archive", + "description": "Connect a DIDWW phone number to a Vogent voice agent over SIP import. Use whenever the user wants a Vogent agent on a real phone number via DIDWW, mentions pairing DIDWW with Vogent, sip_import numbers, sip.vogent.ai, or debugging calls between the two.", + "url": "didww-to-vogent.tar.gz", + "digest": "sha256:1c2227a36a7909cc0fd6c7ebe496c275070b466086a9e0c18614bd05b4df31bd", + "version": "1.0.2", + "documentation": "https://github.com/didww/ai/blob/main/docs/didww-to-vogent.md", + "install": "npx didww-to-vogent" + }, + { + "name": "didww-to-xai", + "type": "archive", + "description": "Point a DIDWW phone number at xAI's Grok voice over SIP. Use whenever the user wants Grok answering a real phone number via DIDWW, mentions sip.voice.x.ai, xAI realtime calls, registering a phone number with xAI, or debugging calls between DIDWW and Grok. Developer-grade: agent behavior is configured per call over a websocket the user's code owns.", + "url": "didww-to-xai.tar.gz", + "digest": "sha256:7d9fbc775ed9718758b43a9afc93e3b8e020f77780fd9226b4c4dee65f0e6c79", + "version": "1.0.2", + "documentation": "https://github.com/didww/ai/blob/main/docs/didww-to-xai.md", + "install": "npx didww-to-xai" + } + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 59be5f2..bb10552 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to the skills in this repository. Each skill is versioned independently in its `package.json`. +## Agent Skills discovery index (2026-10-30) + +- New `.well-known/agent-skills/index.json` in the [Agent Skills discovery](https://github.com/cloudflare/agent-skills-discovery-rfc) format v0.2.0, the same format Telnyx serves at `telnyx.com/.well-known/agent-skills/index.json`. Every skill is a `type: "archive"` entry: a `.tar.gz` with `SKILL.md`, `scripts/`, `references/` and `LICENSE` at the root, and its sha256 `digest`. Extra fields (`version`, `documentation`, `install`) are ignored by clients that do not know them. +- `scripts/build_index.py` generates the folder from `skills/` (descriptions from the SKILL.md frontmatter, versions from `package.json`); archives are rewritten only when their contents change, so digests stay stable. `--check` runs in `scripts/test.sh` and CI. +- `scripts/mirror_index.py` lets didww.com keep its copy current from GitHub on a schedule: it verifies every digest and archive before swapping the new set in, and leaves the live folder untouched on any failure. Handoff for the web team: [`docs/agent-skills-index.md`](docs/agent-skills-index.md). + ## Security and correctness review (2026-10-13) `didww-to-openai-realtime` 1.1.0, `didww-to-vapi` 1.1.0, `didww-to-ultravox` 1.1.0, `didww-to-elevenlabs` 1.1.0, `didww-to-livekit` 1.1.1, and 1.0.2 of `didww-connect`, `didww-to-retell`, `didww-to-vogent` and `didww-to-xai`. Started from an automated review; every finding was reproduced in code and checked against the vendor's own documentation or OpenAPI schema before it was fixed, and the request shapes of all scripts were rechecked against those schemas. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1a3f263..2b4c59a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,8 @@ skills// one Claude Code skill = one npm package tests/ request-shape tests against stubbed HTTP; no keys, no network package.json npm name = skill name; files whitelist docs/ pages for doc.didww.com, one per skill -scripts/ family-wide test and publish runners +scripts/ family-wide test and publish runners, the index builder and the website mirror +.well-known/agent-skills/ generated: discovery index.json + .tar.gz per skill (never edit by hand) ``` ## Before you open a pull request @@ -24,6 +25,7 @@ scripts/ family-wide test and publish runners 3. Never commit credentials, account identifiers or real phone numbers. Tests use stubbed HTTP and fake keys. 4. Verify platform facts against the platform's current documentation and update the "verified" date at the end of the skill's `SKILL.md`. 5. If you change a skill's behaviour, update its page in `docs/` in the same change. +6. Run `python3 scripts/build_index.py` and commit `.well-known/` with the change. CI fails while the index or an archive is out of date with `skills/`. ## Adding a platform diff --git a/README.md b/README.md index 1c22a7f..6aaf958 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Open-source tools from [DIDWW](https://www.didww.com/) for building AI voice age | [`skills/`](skills/) | Nine Claude Code agent skills that connect a DIDWW number to an AI voice platform. Each is its own npm package. | | [`docs/`](docs/) | Documentation pages for the skills, written for [doc.didww.com](https://doc.didww.com/). | | [`scripts/`](scripts/) | Family-wide test and publish runners used by maintainers and CI. | +| [`.well-known/agent-skills/`](.well-known/agent-skills/) | The [Agent Skills discovery](https://github.com/cloudflare/agent-skills-discovery-rfc) index plus one archive per skill, generated from `skills/`, for didww.com to serve at `/.well-known/agent-skills/index.json`. | ## Skills @@ -34,6 +35,8 @@ npx didww-connect npx didww-to-livekit ``` +Any agent that reads the Agent Skills discovery format can also find all of them from one URL, [`.well-known/agent-skills/index.json`](.well-known/agent-skills/index.json), which lists every skill with a sha256-verified `.tar.gz`. + Straight from this repository, without the npm registry: `npx skills add didww/ai --skill `, or `npx skills add didww/ai --list` to see all nine. Restart Claude Code after installing. ### Requirements @@ -51,6 +54,7 @@ The installers copy files and nothing else. The skills store no credentials; pla bash scripts/test.sh # every skill's checks: stdlib Python plus node, no network, no keys bash scripts/publish.sh # publish all nine to npm (after npm login) bash scripts/publish.sh didww-to-vapi # publish one +python3 scripts/build_index.py # regenerate .well-known/agent-skills/ after changing a skill ``` GitHub Actions runs the same tests on every push and pull request. See [CONTRIBUTING.md](CONTRIBUTING.md) for the skill layout, versioning and how to add a platform, and [CHANGELOG.md](CHANGELOG.md) for releases. diff --git a/docs/agent-skills-index.md b/docs/agent-skills-index.md new file mode 100644 index 0000000..58b3392 --- /dev/null +++ b/docs/agent-skills-index.md @@ -0,0 +1,53 @@ +# Serving the agent skills index on didww.com + +For the DIDWW web team. The goal is one URL that lets AI agents and skill directories find every DIDWW agent skill: + +``` +https://www.didww.com/.well-known/agent-skills/index.json +``` + +It uses the [Agent Skills discovery](https://github.com/cloudflare/agent-skills-discovery-rfc) format (v0.2.0), the same one Telnyx serves at `https://telnyx.com/.well-known/agent-skills/index.json`. Nothing on the site is written by hand: the files are generated in the [didww/ai](https://github.com/didww/ai) repository and the site keeps a copy. + +## What gets served + +The folder [`.well-known/agent-skills/`](../.well-known/agent-skills/) in the repository, as is: + +| File | Content-Type | +|---|---| +| `index.json` | `application/json` | +| `.tar.gz` (one per skill) | `application/gzip` | + +The index refers to each archive by a relative URL (`didww-connect.tar.gz`), so the files must sit side by side under `/.well-known/agent-skills/`. + +## Keeping it current + +Run the mirror script on a schedule, for example hourly from cron. It needs Python 3 and nothing else: + +```bash +python3 mirror_index.py --dest /path/to/webroot/.well-known/agent-skills +``` + +Download [`scripts/mirror_index.py`](../scripts/mirror_index.py) once, or run it from a clone of the repository. It reads the index from GitHub (`main` branch), downloads every archive, checks each sha256 digest and that every archive is safe to unpack, then replaces the folder in a single step. If anything fails (network, a digest mismatch, a malformed archive) it exits with code 1 and leaves the live folder exactly as it was. It only fetches files that sit next to the index on GitHub. + +Example crontab line: + +``` +17 * * * * python3 /opt/didww-skills/mirror_index.py --dest /var/www/didww.com/.well-known/agent-skills >> /var/log/didww-skills-mirror.log 2>&1 +``` + +## Web server settings + +- The Content-Types above. With nginx, `location ~ ^/\.well-known/agent-skills/.+\.tar\.gz$ { types { } default_type application/gzip; }` covers the archives; `.json` is mapped to `application/json` by the default `mime.types`. +- `GET` and `HEAD`, and `404` for files that do not exist. +- `Cache-Control: public, max-age=3600` matches an hourly mirror. +- `Access-Control-Allow-Origin: *`, so browser-based agents can read the index. +- No redirect from `didww.com` to `www.didww.com` is required, but agents follow redirects if there is one. + +## Checking it + +```bash +curl -sI https://www.didww.com/.well-known/agent-skills/index.json # 200, application/json +curl -s https://www.didww.com/.well-known/agent-skills/index.json | python3 -m json.tool | head +``` + +Every `digest` in the index must equal `sha256:` plus the SHA-256 of the archive the site serves. The mirror guarantees this as long as nothing else writes to the folder. diff --git a/scripts/build_index.py b/scripts/build_index.py new file mode 100644 index 0000000..e2ad51c --- /dev/null +++ b/scripts/build_index.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +"""Builds .well-known/agent-skills/: the Agent Skills discovery index (v0.2.0) +plus one .tar.gz per skill, so any site can serve the family from one folder. + + python3 scripts/build_index.py write index.json and archives + python3 scripts/build_index.py --check fail if they are out of date (CI) + +Each archive holds what bin/install.js installs (SKILL.md, scripts/, +references/) plus LICENSE, at the archive root as the spec requires. +Archives are rewritten only when their contents change, so digests stay +put between builds. Spec: github.com/cloudflare/agent-skills-discovery-rfc +""" +import glob, gzip, hashlib, io, json, os, re, sys, tarfile + +ROOT = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) +OUT = os.path.join(ROOT, ".well-known", "agent-skills") +SCHEMA = "https://schemas.agentskills.io/discovery/0.2.0/schema.json" +REPO = "https://github.com/didww/ai" +PARTS = ["SKILL.md", "LICENSE", "scripts", "references"] +SKIP = re.compile(r"(^|/)(__pycache__|\.DS_Store|.*\.pyc)(/|$)") +NAME = re.compile(r"^[a-z0-9]+(-[a-z0-9]+)*$") + +def frontmatter(path): + """name and description from SKILL.md; handles plain and folded (>) scalars.""" + text = open(path, encoding="utf-8").read() + m = re.match(r"^---\n(.*?)\n---\n", text, re.S) + if not m: + sys.exit(f"{path}: no YAML frontmatter") + fields, key, lines = {}, None, [] + for line in m.group(1).split("\n") + ["end:"]: + top = re.match(r"^([A-Za-z_-]+):\s*(.*)$", line) + if top: + if key: + fields[key] = re.sub(r"\s+", " ", " ".join(lines)).strip() + key, value = top.groups() + lines = [] if value in (">", ">-", "|", "|-") else [value.strip().strip('"\'')] + elif key: + lines.append(line.strip()) + return fields + +def members(skill_dir): + """(archive path, mode, bytes) for every file the archive should hold, sorted.""" + files = [] + for part in PARTS: + src = os.path.join(skill_dir, part) + paths = [src] if os.path.isfile(src) else sorted( + os.path.join(p, f) for p, _, fs in os.walk(src) for f in fs) + for p in paths: + rel = os.path.relpath(p, skill_dir).replace(os.sep, "/") + if SKIP.search(rel) or os.path.islink(p): + continue + mode = 0o755 if os.stat(p).st_mode & 0o111 else 0o644 + files.append((rel, mode, open(p, "rb").read())) + return sorted(files) + +def pack(files): + """Deterministic tar.gz: fixed owner and times, no wrapper directory.""" + raw = io.BytesIO() + with tarfile.open(fileobj=raw, mode="w", format=tarfile.PAX_FORMAT) as tar: + for rel, mode, data in files: + info = tarfile.TarInfo(rel) + info.size, info.mode, info.mtime = len(data), mode, 0 + info.uid = info.gid = 0; info.uname = info.gname = "" + tar.addfile(info, io.BytesIO(data)) + out = io.BytesIO() + with gzip.GzipFile(fileobj=out, mode="wb", mtime=0, filename="") as gz: + gz.write(raw.getvalue()) + return out.getvalue() + +def unpack(blob): + """(path, mode, bytes) of a built archive, to compare with the sources.""" + with tarfile.open(fileobj=io.BytesIO(blob), mode="r:gz") as tar: + return sorted((m.name, m.mode, tar.extractfile(m).read()) for m in tar.getmembers() if m.isfile()) + +def build(check): + stale, entries = [], [] + for skill_md in sorted(glob.glob(os.path.join(ROOT, "skills", "*", "SKILL.md"))): + skill_dir = os.path.dirname(skill_md) + folder = os.path.basename(skill_dir) + fm = frontmatter(skill_md) + name, desc = fm.get("name", ""), fm.get("description", "") + if name != folder or not NAME.match(name) or len(name) > 64: + sys.exit(f"{skill_md}: name '{name}' must match the folder and the Agent Skills naming rules") + if not desc or len(desc) > 1024: + sys.exit(f"{skill_md}: description must be 1 to 1024 characters (has {len(desc)})") + version = json.load(open(os.path.join(skill_dir, "package.json")))["version"] + files = members(skill_dir) + archive = os.path.join(OUT, f"{name}.tar.gz") + blob = open(archive, "rb").read() if os.path.isfile(archive) else None + if blob is None or unpack(blob) != files: + stale.append(os.path.relpath(archive, ROOT)) + blob = pack(files) + if not check: + os.makedirs(OUT, exist_ok=True) + open(archive, "wb").write(blob) + entries.append({ + "name": name, + "type": "archive", + "description": desc, + "url": f"{name}.tar.gz", + "digest": "sha256:" + hashlib.sha256(blob).hexdigest(), + "version": version, + "documentation": f"{REPO}/blob/main/docs/{name}.md" + if os.path.isfile(os.path.join(ROOT, "docs", f"{name}.md")) + else f"{REPO}/tree/main/skills/{name}", + "install": f"npx {name}", + }) + index = { + "$schema": SCHEMA, + "name": "DIDWW Agent Skills", + "description": "Official DIDWW agent skills: put an AI voice agent on a real DIDWW phone " + "number with any major voice AI platform, through the DIDWW MCP " + "(https://api.didww.com/mcp).", + "repository": REPO, + "homepage": "https://www.didww.com/", + "skills": entries, + } + text = json.dumps(index, indent=2, ensure_ascii=False) + "\n" + index_path = os.path.join(OUT, "index.json") + current = open(index_path, encoding="utf-8").read() if os.path.isfile(index_path) else None + if current != text: + stale.append(os.path.relpath(index_path, ROOT)) + if not check: + os.makedirs(OUT, exist_ok=True) + open(index_path, "w", encoding="utf-8").write(text) + # Archives of skills that no longer exist. + known = {f"{e['name']}.tar.gz" for e in entries} | {"index.json"} + for extra in sorted(set(os.listdir(OUT)) - known if os.path.isdir(OUT) else []): + if extra.endswith(".tar.gz"): + stale.append(os.path.relpath(os.path.join(OUT, extra), ROOT)) + if not check: + os.remove(os.path.join(OUT, extra)) + return entries, stale + +if __name__ == "__main__": + check = "--check" in sys.argv[1:] + entries, stale = build(check) + if check: + if stale: + print("Out of date: " + ", ".join(stale)) + print("Run: python3 scripts/build_index.py, then commit .well-known/") + sys.exit(1) + print(f"PASS .well-known/agent-skills is current ({len(entries)} skills)") + else: + print(f"{len(entries)} skills; " + (f"updated {', '.join(stale)}" if stale else "nothing changed")) diff --git a/scripts/mirror_index.py b/scripts/mirror_index.py new file mode 100644 index 0000000..e0e9ad4 --- /dev/null +++ b/scripts/mirror_index.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +"""Mirrors the DIDWW agent skills index onto a web server, for cron. + + python3 scripts/mirror_index.py --dest /var/www/didww.com/.well-known/agent-skills + +Downloads index.json and every archive it lists from GitHub (or --source), +checks each sha256 digest and that every archive is safe to unpack (SKILL.md +at the root, no absolute paths, no "..", no links), then swaps the new folder +in at once. On any failure the live folder is left untouched and the exit +code is 1, so a half-updated or tampered set is never served. Stdlib only. +""" +import argparse, hashlib, io, json, os, shutil, sys, tarfile, tempfile, urllib.parse, urllib.request + +DEFAULT_SOURCE = "https://raw.githubusercontent.com/didww/ai/main/.well-known/agent-skills/index.json" +SCHEMA = "https://schemas.agentskills.io/discovery/0.2.0/schema.json" +MAX_BYTES = 20 * 1024 * 1024 + +def fetch(url): + if "://" not in url: # a local path, for tests and manual runs + return open(url, "rb").read() + with urllib.request.urlopen(urllib.request.Request(url, headers={"User-Agent": "didww-skills-mirror"}), timeout=60) as r: + data = r.read(MAX_BYTES + 1) + if len(data) > MAX_BYTES: + raise ValueError(f"{url}: larger than {MAX_BYTES} bytes") + return data + +def check_archive(name, blob): + with tarfile.open(fileobj=io.BytesIO(blob), mode="r:gz") as tar: + names = [] + for m in tar.getmembers(): + if m.name.startswith("/") or ".." in m.name.split("/") or not (m.isfile() or m.isdir()): + raise ValueError(f"{name}: unsafe archive member {m.name!r}") + names.append(m.name) + if "SKILL.md" not in names: + raise ValueError(f"{name}: no SKILL.md at the archive root") + +def mirror(source, dest): + index_bytes = fetch(source) + index = json.loads(index_bytes) + if index.get("$schema") != SCHEMA: + raise ValueError(f"unexpected $schema {index.get('$schema')!r}") + files = {"index.json": index_bytes} + remote = "://" in source + base = source.rsplit("/", 1)[0] if remote else os.path.dirname(os.path.abspath(source)) + for skill in index["skills"]: + url = skill["url"] + # Only plain file names next to the index: the mirror never fetches other hosts. + if "/" in url or "\\" in url or url.startswith(".") or not url.endswith(".tar.gz"): + raise ValueError(f"{skill['name']}: url {url!r} is not a file next to the index") + blob = fetch(f"{base}/{urllib.parse.quote(url)}" if remote else os.path.join(base, url)) + digest = "sha256:" + hashlib.sha256(blob).hexdigest() + if digest != skill["digest"]: + raise ValueError(f"{skill['name']}: digest mismatch ({digest} != {skill['digest']})") + check_archive(skill["name"], blob) + files[url] = blob + dest = os.path.abspath(dest) + parent = os.path.dirname(dest) + os.makedirs(parent, exist_ok=True) + staging = tempfile.mkdtemp(prefix=".agent-skills-new-", dir=parent) + try: + for fname, data in files.items(): + with open(os.path.join(staging, fname), "wb") as f: + f.write(data) + os.chmod(os.path.join(staging, fname), 0o644) + os.chmod(staging, 0o755) + except Exception: + shutil.rmtree(staging, ignore_errors=True) + raise + old = None + if os.path.exists(dest): + old = tempfile.mkdtemp(prefix=".agent-skills-old-", dir=parent) + os.rmdir(old) + os.rename(dest, old) + os.rename(staging, dest) + if old: + shutil.rmtree(old) + return len(index["skills"]) + +if __name__ == "__main__": + ap = argparse.ArgumentParser(description=__doc__.split("\n")[0]) + ap.add_argument("--dest", required=True, help="folder served as /.well-known/agent-skills/") + ap.add_argument("--source", default=DEFAULT_SOURCE, help="index.json URL or local path") + args = ap.parse_args() + try: + n = mirror(args.source, args.dest) + except Exception as e: + print(f"Mirror failed, live folder unchanged: {e}", file=sys.stderr) + sys.exit(1) + print(f"Mirrored {n} skills to {args.dest}") diff --git a/scripts/test.sh b/scripts/test.sh index adc4ff2..d5a73f9 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -4,3 +4,4 @@ set -euo pipefail cd "$(dirname "$0")/.." for d in skills/*/; do echo "== ${d%/}"; bash "${d}test.sh"; echo; done echo "== installers"; python3 -B scripts/test_installers.py +echo; echo "== discovery index"; python3 -B scripts/test_index.py diff --git a/scripts/test_index.py b/scripts/test_index.py new file mode 100644 index 0000000..0aa3e81 --- /dev/null +++ b/scripts/test_index.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +"""Tests for the agent skills discovery index and its website mirror. + +Checks that .well-known/agent-skills/ is current, that every entry follows the +discovery spec v0.2.0 (names, descriptions, sha256 digests of the archives, +SKILL.md at the archive root), that the build is deterministic, and that +mirror_index.py publishes a good set but refuses a tampered one while leaving +the live folder untouched. Offline; nothing outside a temporary directory. +""" +import glob, hashlib, io, json, os, re, shutil, subprocess, sys, tarfile, tempfile + +ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +OUT = os.path.join(ROOT, ".well-known", "agent-skills") +sys.path.insert(0, os.path.join(ROOT, "scripts")) +import build_index, mirror_index + +results = [] +def check(name, ok, detail=""): + results.append(bool(ok)); print(f"{'PASS' if ok else 'FAIL'} {name} {detail}") + +r = subprocess.run([sys.executable, "-B", os.path.join(ROOT, "scripts", "build_index.py"), "--check"], + capture_output=True, text=True) +check("index and archives are current", r.returncode == 0, (r.stdout + r.stderr).strip()[-300:]) + +index = json.load(open(os.path.join(OUT, "index.json"))) +skills = sorted(os.path.basename(os.path.dirname(p)) for p in + glob.glob(os.path.join(ROOT, "skills", "*", "SKILL.md"))) +check("$schema is discovery v0.2.0", index.get("$schema") == build_index.SCHEMA) +check("one entry per skill folder", [e["name"] for e in index["skills"]] == skills, + [e["name"] for e in index["skills"]]) +for e in index["skills"]: + blob = open(os.path.join(OUT, e["url"]), "rb").read() + with tarfile.open(fileobj=io.BytesIO(blob), mode="r:gz") as tar: + names = tar.getnames() + skill_md = tar.extractfile("SKILL.md").read() if "SKILL.md" in names else b"" + src_md = open(os.path.join(ROOT, "skills", e["name"], "SKILL.md"), "rb").read() + check(f"{e['name']}: spec fields and naming", + e["type"] == "archive" and re.match(r"^[a-z0-9]+(-[a-z0-9]+)*$", e["name"]) + and 0 < len(e["description"]) <= 1024 and re.match(r"^sha256:[0-9a-f]{64}$", e["digest"])) + check(f"{e['name']}: digest is the archive's sha256", + e["digest"] == "sha256:" + hashlib.sha256(blob).hexdigest()) + check(f"{e['name']}: SKILL.md at the root, same bytes as the source, scripts included, no caches", + skill_md == src_md and any(n.startswith("scripts/") for n in names) + and not any(n.startswith("/") or ".." in n.split("/") or "__pycache__" in n for n in names)) + check(f"{e['name']}: description matches SKILL.md frontmatter", + e["description"] == build_index.frontmatter(os.path.join(ROOT, "skills", e["name"], "SKILL.md"))["description"]) + files = build_index.members(os.path.join(ROOT, "skills", e["name"])) + check(f"{e['name']}: build is deterministic", build_index.pack(files) == build_index.pack(files)) + +with tempfile.TemporaryDirectory() as tmp: + live = os.path.join(tmp, "www", "agent-skills") + code = mirror_index.mirror(os.path.join(OUT, "index.json"), live) + check("mirror publishes every skill with verified digests", + code == len(skills) and sorted(os.listdir(live)) == sorted([e["url"] for e in index["skills"]] + ["index.json"])) + before = {f: open(os.path.join(live, f), "rb").read() for f in os.listdir(live)} + + bad = os.path.join(tmp, "bad"); shutil.copytree(OUT, bad) + first = index["skills"][0]["url"] + with open(os.path.join(bad, first), "ab") as f: + f.write(b"tampered") + try: + mirror_index.mirror(os.path.join(bad, "index.json"), live); refused = False + except ValueError as err: + refused = "digest mismatch" in str(err) + after = {f: open(os.path.join(live, f), "rb").read() for f in os.listdir(live)} + check("mirror refuses a tampered archive and leaves the live folder as it was", refused and after == before) + + evil = os.path.join(tmp, "evil"); shutil.copytree(OUT, evil) + idx = json.load(open(os.path.join(evil, "index.json"))) + idx["skills"][0]["url"] = "https://example.com/x.tar.gz" + json.dump(idx, open(os.path.join(evil, "index.json"), "w")) + try: + mirror_index.mirror(os.path.join(evil, "index.json"), live); refused = False + except ValueError: + refused = True + check("mirror refuses URLs pointing at other hosts", refused) + + raw = io.BytesIO() + with tarfile.open(fileobj=raw, mode="w:gz") as tar: + for n in ("SKILL.md", "../escape"): + info = tarfile.TarInfo(n); info.size = 1; tar.addfile(info, io.BytesIO(b"x")) + try: + mirror_index.check_archive("t", raw.getvalue()); refused = False + except ValueError: + refused = True + check("mirror refuses an archive with path traversal", refused) + +print(f"\n{sum(results)}/{len(results)} passed") +sys.exit(0 if all(results) else 1) From 6fc066c8dfd20322cb36a6e21e9061c7cf9117ed Mon Sep 17 00:00:00 2001 From: allexp1 Date: Fri, 30 Oct 2026 17:08:12 +0200 Subject: [PATCH 2/2] mirror_index: https-only sources, keep every write inside the staging folder Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01EkqDrNJyC24ZuqGd3731Ay --- scripts/mirror_index.py | 10 ++++++++-- scripts/test_index.py | 6 ++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/scripts/mirror_index.py b/scripts/mirror_index.py index e0e9ad4..bd62ceb 100644 --- a/scripts/mirror_index.py +++ b/scripts/mirror_index.py @@ -18,6 +18,8 @@ def fetch(url): if "://" not in url: # a local path, for tests and manual runs return open(url, "rb").read() + if urllib.parse.urlparse(url).scheme != "https": + raise ValueError(f"{url}: only https sources are allowed") with urllib.request.urlopen(urllib.request.Request(url, headers={"User-Agent": "didww-skills-mirror"}), timeout=60) as r: data = r.read(MAX_BYTES + 1) if len(data) > MAX_BYTES: @@ -59,9 +61,13 @@ def mirror(source, dest): staging = tempfile.mkdtemp(prefix=".agent-skills-new-", dir=parent) try: for fname, data in files.items(): - with open(os.path.join(staging, fname), "wb") as f: + # Names come from the downloaded index: keep every write inside staging. + target = os.path.realpath(os.path.join(staging, os.path.basename(fname))) + if os.path.commonpath([target, os.path.realpath(staging)]) != os.path.realpath(staging): + raise ValueError(f"{fname}: would be written outside {dest}") + with open(target, "wb") as f: f.write(data) - os.chmod(os.path.join(staging, fname), 0o644) + os.chmod(target, 0o644) os.chmod(staging, 0o755) except Exception: shutil.rmtree(staging, ignore_errors=True) diff --git a/scripts/test_index.py b/scripts/test_index.py index 0aa3e81..91e32a6 100644 --- a/scripts/test_index.py +++ b/scripts/test_index.py @@ -75,6 +75,12 @@ def check(name, ok, detail=""): refused = True check("mirror refuses URLs pointing at other hosts", refused) + try: + mirror_index.fetch("file:///etc/passwd"); refused = False + except ValueError: + refused = True + check("mirror refuses non-https sources", refused) + raw = io.BytesIO() with tarfile.open(fileobj=raw, mode="w:gz") as tar: for n in ("SKILL.md", "../escape"):