From 3a8b6cc56c32ef97f6fcef39901baa4b6e9e16bc Mon Sep 17 00:00:00 2001 From: Time Date: Mon, 19 Oct 2026 13:56:19 +0000 Subject: [PATCH] card #96: kept ventures/mdecks/README.md, ventures/mdecks/tools/whop-build.sh, ventures/mdecks/tools/whop-check.sh (generated) --- ventures/mdecks/README.md | 3 +++ ventures/mdecks/tools/whop-build.sh | 10 +++++++++- ventures/mdecks/tools/whop-check.sh | 13 ++++++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/ventures/mdecks/README.md b/ventures/mdecks/README.md index d9ad3d6..067f8d2 100644 --- a/ventures/mdecks/README.md +++ b/ventures/mdecks/README.md @@ -68,6 +68,9 @@ Views to register on Whop, with the path Whop fills the ID into: |---|---|---| | Experience (member view) | `/experiences/[experienceId]` | the editor and presenter | | Dashboard (creator's view) | `/dashboard/[companyId]` | the same editor, with **Copy prompt for your agent** | +| Skills (agent-facing) | `/.well-known/skills/index.json` | an index pointing at `/SKILL.md`, the agent skill | + +The skills view has no documented format on Whop yet. It follows the layout Whop's own docs use (`docs.whop.com/.well-known/skills/index.json` pointing at SKILL.md files), which is an assumption: check it against Whop's docs when they publish one. The build writes the index from `.well-known/skills/index.json` with its url made host-relative (`/SKILL.md`). No other view is declared (there is no `openapi` view yet). diff --git a/ventures/mdecks/tools/whop-build.sh b/ventures/mdecks/tools/whop-build.sh index 44d2780..1746232 100644 --- a/ventures/mdecks/tools/whop-build.sh +++ b/ventures/mdecks/tools/whop-build.sh @@ -8,6 +8,7 @@ # The site is the editor and presenter only (no pricing or marketing sections), served at: # /experiences/ member view # /dashboard/ creator's dashboard view +# /.well-known/skills/index.json + /SKILL.md skills view (agent-facing; Whop's own docs use this layout) # A static host resolves a dynamic segment only with a real directory or a rewrite, so the zip ships # experiences/index.html, dashboard/index.html and a 404.html that are all the same app, with absolute asset # paths: any /experiences/ or /dashboard/ (however deep) lands on the app. @@ -20,7 +21,7 @@ out=$(cd "$out" && pwd) zip="$out/mdeck-whop.zip" HERE="$here" ZIP="$zip" python3 - <<'PY' -import os, re, zipfile +import json, os, re, zipfile here, target = os.environ["HERE"], os.environ["ZIP"] @@ -50,7 +51,14 @@ if 'fetch("SKILL.md")' not in app: raise SystemExit("whop-build: app.js no longer fetches SKILL.md") app = app.replace('fetch("SKILL.md")', 'fetch("/SKILL.md")') +# The skills view: the repo's index with its url made host-relative, so it points at the SKILL.md in this build. +index = json.loads(read(".well-known/skills/index.json")) +for skill in index["skills"]: + skill["url"] = "/SKILL.md" +index = json.dumps(index, indent=2) + "\n" + files = { + ".well-known/skills/index.json": index, "index.html": page, "experiences/index.html": page, "dashboard/index.html": page, diff --git a/ventures/mdecks/tools/whop-check.sh b/ventures/mdecks/tools/whop-check.sh index 68ed88b..fa5aad4 100644 --- a/ventures/mdecks/tools/whop-check.sh +++ b/ventures/mdecks/tools/whop-check.sh @@ -14,7 +14,7 @@ sh "$here/whop-build.sh" "$work/out" python3 -c 'import sys, zipfile; zipfile.ZipFile(sys.argv[1]).extractall(sys.argv[2])' "$work/out/mdeck-whop.zip" "$work/site" SITE="$work/site" python3 - <<'PY' -import http.server, os, threading, urllib.request, urllib.error +import http.server, json, os, threading, urllib.request, urllib.error site = os.environ["SITE"] @@ -66,6 +66,17 @@ for path, needle in [("/app.js", 'fetch("/SKILL.md")'), ("/whop.js", "data-view" print("%-22s %s asset ok: %s" % (path, status, "yes" if ok else "NO")) failed += not ok +status, body = get("/.well-known/skills/index.json") +skills = json.loads(body)["skills"] if status == 200 else [] +for skill in skills: + s2, b2 = get(skill["url"]) + ok = s2 == 200 and skill["files"] == ["SKILL.md"] and b2 == get("/SKILL.md")[1] + print("%-22s index -> %s %s: %s" % ("/.well-known/skills", skill["url"], s2, "yes" if ok else "NO")) + failed += not ok +if not skills: + print("skills index missing") + failed += 1 + status, body = get("/experiences/abc") for gone in ("Get early access", "Opens a public GitHub issue", "Pricing", "How it works"): if gone in body: