Agent skill
handbill <file> uploads one self-contained HTML file — or a markdown file, which it renders to one first — and prints its public URL. Nothing else goes to stdout. The URL is content-addressed — the first 12 hex characters of the file’s sha256 — so the same bytes always give the same link and never a duplicate; a changed file is a new link, and a published link never changes under its reader.
handbill plan.html # → https://<hash>.<zone>handbill notes.md # markdown, rendered to a styled page firstcat plan.html | handbill - # from stdin, no temp filecat notes.md | handbill - --markdownhandbill plan.html --json # → { "hash", "url", "created" }On success, reply to the user with the URL and stop.
Before publishing
- One file per link. A
.mdor.markdownfile is rendered by the CLI into one self-contained page — built-in light/dark stylesheet, no external requests — and that page is what gets published; the deployment never sees markdown. Anything else goes up byte for byte, so HTML must be self-contained: a file that references local images, stylesheets, or scripts will 404 on the page. - Write markdown when the deliverable is prose. It is shorter than hand-writing a document shell and reads well in both themes. Reach for HTML when the page needs its own design or any JavaScript.
- It becomes public. The link is unguessable and served with
noindex, but anyone holding it can read it. Do not publish secrets, tokens, customer data, or internal material the user did not explicitly ask to share. When in doubt, say what you are about to publish and let the user confirm. - Configuration must exist.
~/.config/handbill/config.jsonwith{ "endpoint", "token" }, or the environment variablesHANDBILL_ENDPOINTandHANDBILL_TOKEN. If neither is present, tell the user — do not go looking for a token elsewhere.
List what is published
handbill list # one line per page, newest first: date, url, titlehandbill list --jsonTitles come from the document’s <title> — for markdown, from the first H1, or the filename when there is none — so give every page a meaningful one. Use this when the user asks what has been published or has lost a link.
Unpublish
handbill remove <url-or-hash>Idempotent: succeeds even if the page is already gone. Use it immediately if something sensitive was published by mistake, then tell the user.
Name a page
handbill alias plan <url-or-hash> # → https://plan.<zone>, serving that page from now onhandbill alias list # one line per alias: url, hashhandbill alias remove plan # the name stops answering; the page stays publishedAn alias is a living name: point plan at the new hash after each revision and the reader’s link keeps showing the latest version, while every hash link stays exactly what it was. Only use one when the user asks for a stable or readable link, and say two things when you do: names are guessable (a hash is unguessable; plan is a word anyone who knows the zone can try), and the feature is opt-in — a deployment without its KV binding answers every alias command with one sentence saying how to enable it. Report that sentence to the user; do not work around it. One more thing to expect: the name works the moment alias prints its URL, but alias list can take up to a minute to show a fresh name (the deployment’s key listing is eventually consistent). “No aliases set.” right after a successful alias is that lag — trust the printed URL, do not set the name again.
Showing the page
--open on handbill <file> and handbill alias opens the printed URL in the user’s default browser after printing it. stdout is still exactly one line. Use it only when the user asked to see the page, not by default.
When something fails
- Every failure is one sentence on stderr and a non-zero exit (
{ "error", "message" }on stderr with--json). Report it; do not retry in a loop. handbill doctorchecks, in order: config present, token present, endpoint reachable, token accepted, wildcard TLS valid — each with a one-line fix. Run it first when a command fails for a reason that is not the file.command not found: handbill→ the CLI is not installed.npm i -g handbill, or from a checkout of the repository:bun run --cwd apps/cli build && npm i -g ./apps/cli.- A
5xxfrom the endpoint is the deployment’s problem (apps/workerin the repository), not the file’s. Tell the user and stop.
Installing this skill
Copy or symlink this directory to where the agent reads skills from:
# Claude Codeln -s "$PWD/skills/handbill" ~/.claude/skills/handbill# Codexln -s "$PWD/skills/handbill" ~/.agents/skills/handbillThe skill only needs handbill on PATH and a configured endpoint and token.