Install
openclaw skills install @zzir/gists-pagePublish HTML/JS/CSS demos as GitHub Gists and share gists.page preview links. Use when the user wants to share or preview a demo online, publish a snippet to gist, get a shareable preview link, or mentions gists.page or gist preview.
openclaw skills install @zzir/gists-pagegists.page is a static site + Service Worker that previews GitHub Gists: the browser intercepts requests, fetches gist content from the GitHub API/raw endpoints, and renders it with correct MIME types. Publishing a demo means producing a gist id, then handing out the preview link.
index.htmlInline CSS in <style> and JS in <script>, and ship a single index.html.
One file publishes in a single call on every path below, and none of the flat-gist
constraints (no directories, basename folding, rename conflicts) can bite.
Multi-file gists are fully supported — relative references resolve between files —
so publish an existing multi-file demo as-is rather than rewriting it; just don't
author new demos as multi-file when inlining is trivial.
https://gists.page/{gist_id}/ — renders index.html (or an HTML first file);
otherwise a gist-page-style overview of all fileshttps://gists.page/{gist_id}/{file_name} — renders a specific file (URL-encode the name)Several ways to create a gist — use the first one available in this session:
1. gh CLI — if installed and authenticated (gh auth status; it also picks up
GH_TOKEN/GITHUB_TOKEN env vars):
# Creates a secret gist by default (link works, but unlisted/unsearchable)
gh gist create index.html
# Multi-file works too: gh gist create index.html app.js style.css
# Add --public for a public gist; the last path segment of the output URL is the gist_id
2. GitHub MCP tools — if the session has them, look for gist tools
(create_gist / update_gist on the official GitHub MCP server) and follow their
schemas. The official server's gist tools take one file per call — a single-file
demo publishes in one create_gist call; for multi-file, create the gist with the
entry file, then add each remaining file with update_gist.
3. GitHub REST API via curl — needs a token with the gist scope (classic PAT)
or Gists read/write (fine-grained). Check $GH_TOKEN / $GITHUB_TOKEN before asking
the user for one; anonymous gist creation is not supported by the API.
jq -n --rawfile h index.html '{public: false, files: {"index.html": {content: $h}}}' |
curl -sS -X POST https://api.github.com/gists \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
-d @- | jq -r '.id'
--rawfile handles JSON escaping (multi-file: one --rawfile and one files entry
per file); without jq, build the body with a python one-liner — never splice file
contents into a hand-assembled JSON string.
4. None of the above — ask the user to create the gist manually at https://gist.github.com (paste the files there) and reply with the gist URL or id.
Preview link = https://gists.page/<gist_id>/.
gh gist edit <id> --add <file> uploads that file (adds or replaces). Bare
gh gist edit <id> opens an interactive $EDITOR — avoid in agent sessions.update_gist (or equivalent), one file per call.PATCH https://api.github.com/gists/<id> with the same files body shape as
creation; set a file's value to null to delete it.https://gist.github.com/<id>.git, commit, push (HTTPS auth: any
username, token as password).Verify uploads with curl -s https://api.github.com/gists/<id> (check the files
keys; add -H "Authorization: Bearer $GITHUB_TOKEN" if anonymously rate-limited) —
do NOT verify by curling the preview link (see below). If a browser tool is available,
open the preview link to confirm rendering.
The first three bullets only apply to multi-file demos.
Gist does not support directories), and the web UI can't create them either.
Flatten files before uploading../css/style.css onto its basename style.css (flat names are
unique in a gist, so the mapping is unambiguous).css/a.js + js/a.js). A gist can hold only one a.js — rename and update
references before publishing.index.html gets default-page treatment.git push may work (the preview
streams binaries fine); if push is also rejected, use external hosting or data: URIs..html/.htm
run as pages — app entry files must end in .html. Subresource fetches
(./app.js, fetch('./data.json')) always get raw content with
extension-mapped MIME types../app.js, fetch('./data.json')) all work.| Symptom | Cause & fix |
|---|---|
Push rejected: does not support directories | Gists are flat; git mv files to the root and retry — HTML references need no changes |
| Edited the gist but the preview didn't change | Visitor-side 5-minute metadata cache; wait for the TTL to expire |
| curl on a preview link returns a form page | Normal: content renders via the SW; verify through the GitHub API instead |
401/403/404 from POST /gists | Token missing, expired, or lacking the gist scope (classic) / Gists read-write (fine-grained) |
| A file shows rendered markdown/source instead of running | Non-HTML navigations open the viewer; name the entry file .html to run it as a page |
404 saying gists are flat | The file (even after basename folding) isn't in the gist; check the exact name |