slate
Create and publish standalone HTML artifacts through private Slate drafts, and read or manage existing drafts. Use for any HTML report, lesson, document, visual artifact, or preview that is not source
Files1
View on GitHubSKILL.mdSkills/Skills/slate/SKILL.md
GitHubSlate
Slate is a private-by-default service and CLI for publishing static HTML drafts. Each upload returns a stable URL; re-uploading the same file publishes a new version at the same URL. Drafts are only readable by their owner unless uploaded with --public.
HTML artifact owner
Slate is the only delivery path for standalone HTML artifacts. Reports, lessons, generated documents, visual summaries, and one-off previews all use this skill. A temporary local HTML file may exist only as upload staging or as the fallback described below. Do not return a local path when Slate succeeds.
This does not apply to HTML that is source code inside a website or application repository. Keep that source in the project and use its normal build and deployment path.
Uploading is an external write. Read-only auth checks and local staging do not
authorize it. If the current request does not explicitly authorize publishing,
ask immediately before slate upload. Keep the draft private unless the user
explicitly requests public access.
If Slate is unavailable, unauthenticated, or the user requests local-only output, keep the complete HTML in the OS temp directory and return that path. State why Slate was not used. Do not silently choose local delivery.
Auth check
Before any write (upload, disable, delete) or listing, verify auth:
slate whoami
If the slate command is missing, run it via the repo instead: npx github:satyasaibhushan/Slate whoami (same for all other commands). If whoami shows no authenticated account, do not attempt to log in or set keys. For a new HTML artifact, use the declared local fallback and tell the user Slate needs slate auth set <key>. For reads or management of an existing draft, stop because there is no authorized fallback.
Reading drafts
Read drafts with curl only. Never use a browser, computer use, or any other web-fetching tool for Slate URLs — draft URLs serve the uploaded HTML byte-for-byte with no wrapper page, so curl always returns the full content.
Strip any trailing slash and append /raw unless the URL already ends in /raw (an alias for the same bytes, kept as the canonical agent URL). Most drafts are private, so send the owner's API key:
curl -fsSL -H "Authorization: Bearer ${SLATE_API_KEY:-$(python3 -c "import json;print(json.load(open('$HOME/.slate/credentials.json'))['apiKey'])")}" <draft-url>/raw
Public drafts also work without the header. A 401 means the draft is private and the key doesn't own it; a 404 means it doesn't exist or was disabled/deleted. Report the actual status or network error — do not fall back to web search or a browser.
To check metadata without the body, read the response headers (X-Slate-Draft-Id, X-Slate-Draft-Version):
curl -fsSI -H "Authorization: Bearer $SLATE_API_KEY" <draft-url>
Writing drafts
Create a complete static HTML document in the OS temp directory, then upload it after the external-write approval gate:
slate upload ./draft.html --description "short label"
Return the stable Slate URL after a successful upload.
- Re-running
uploadfor the same file creates a new version of the existing draft; pass--newto force a separate new draft instead. --descriptionsets or updates the draft's label; omitting it leaves the existing label untouched.- Visibility: drafts are private by default (owner-only). Pass
--publiconly when the user explicitly asks for a shareable/public link; pass--privateto flip a public draft back. Omitting both keeps the draft's current visibility.
Author drafts as complete static HTML documents: semantic HTML, inline CSS or a <style> block, links to ordinary HTTPS pages, and images from HTTPS or data URLs. Do not include:
- JavaScript of any kind —
<script>tags, inline event handlers,javascript:URLs. The upload API rejects most of these, and the serving CSP (script-src 'none') blocks execution of the rest, so any JS is dead weight. - Forms, iframes/embeds/objects, or meta-refresh redirects (rejected at upload time).
- Secrets, tokens, private URLs, or local filesystem paths.
Privacy
Private drafts are readable only with the owner's API key or a signed-in web session, so work-in-progress content is fine by default. Public drafts are readable by anyone with the URL — before using --public, make sure the content contains nothing from work repositories, no user data, credentials, or internal details. If in doubt, keep it private or ask.
Managing drafts
slate list # account's drafts: repo, version, visibility, updated
slate disable <draft-id> # stop serving (URL returns 404); --reason "why"
slate delete <draft-id> # soft-delete the draft
Only disable or delete a draft when the user asks for it.