page-serve

v2026.09.24

Hand a human a rendered HTML page at a stable HTTPS URL. Registers a portless route for a file or directory (https://NAME.localhost/, never a :port), prints the URL, optionally screenshots it, and tears it down on stop. Use when an agent produced a page a human is meant to open: glyph explainers, playgrounds, decision pages, docs previews. Replaces ad hoc python http.server plus alias patterns that leave servers alive.

GitHub
Install command
npx skhub add yonatangross/page-serve
Markdown
SKILL.md

page-serve, give a human a URL

An agent that renders a page for a human needs a way to hand it over. The pattern that grew in sessions was python3 -m http.server 8991 plus portless alias <name> 8991 typed by hand: no record of the process, no stop, servers outliving the session, and one measured night (2026-09-06) where the same session did it twice and the server was still up the next morning. This skill is that pattern with a state file, a stop, a status, and a loud failure when the URL contract cannot be met.

The contract

  • The URL is https://<name>.localhost/<file>. No port, ever. portless's 443 service owns the port; a :1355 or :8991 in the URL is the pre-service fallback and the skill refuses rather than emit one.
  • One static server per name, on a free loopback port, rooted at the file's directory (so sibling assets resolve) or at the directory you pass.
  • State in .claude/state/page-serve/<name>.json: root, file, port, pid, url, time. status re-measures pid, route, and HTTP on every call; it never trusts the file.
  • Idempotent per name: same name + same root reuses the live server; a different root replaces it; --force on the alias overrides a stale route with the same name.

Usage

page-serve docs/playgrounds/roadmap-2026-09-07.html
page-serve docs/playgrounds/ --name playgrounds
page-serve <path> --screenshot          # agent-browser, returns the png path
page-serve status [--json]
page-serve stop <name>
page-serve stop --all

serve.sh prints url=, name=, port=, pid=, http=, optional screenshot=, and the exact stop= line to paste. Put the url= line in your reply's Open section.

Modes

InvocationScriptWhat happens
<path> [flags]scripts/serve.shprerequisites, server, alias, state, curl check, optional screenshot
status [--json]scripts/status.shone line per served page: server up/dead, route registered/missing, HTTP code
stop <name> or stop --allscripts/stop.shalias removed, server killed, state and screenshot deleted; every step reports

Failure modes, all loud

ConditionExitWhat it says
portless not installed2install line, then portless service install
443 service not responding2portless service status, the operator's launchctl kickstart line, and "do not fall back to a :port URL"
server did not bind3port and log path
alias registration failed2portless's own message, server cleaned up
route up but URL not 2004code, curl rc, and portless list; server left running for inspection
screenshot failed0reported on stderr, page still served, screenshot= line omitted

A page that "served" but does not answer 200 through the proxy is exit 4, not 0, so a caller that only reads the exit code cannot report a dead link as done.

Screenshot

With agent-browser installed the default is to take one (--no-screenshot to skip; --screenshot to insist and get a stderr line if it is missing). The png lands beside the state file. The screenshot is evidence the page rendered, not proof it rendered correctly: read the image before claiming the page looks right (the glyph skill's rule 1).

What this is not

  • Not a dev server. For a framework app with hot reload use dev, which wraps the app's own dev command in portless. This skill serves static files.
  • Not a publisher. Nothing leaves the machine; .localhost resolves locally only.
  • Not a docs-site deploy. Lab pages under docs/site/public/lab/ still ship through the docs-site build; this skill is for the hand-over before or beside that.

Retiring the old pattern (#3900)

Any skill or page that tells an agent to run python3 -m http.server or to type portless alias by hand should say page-serve <path> instead. As of this skill's first release, grep -rln 'http.server' src/skills is empty; the pattern lived in session habits and in hq-ext, so the sweep is glyph, playground, visualize-plan and expect (the four that hand a human a page) plus hq-ext's glyph.

Related skills

  • dev, the dev-loop sibling for framework apps (portless wrapping a dev command)
  • portless (the reference skill, model-invoked): service install, LAN mode, gotchas
  • glyph, visualize-plan, playground, the producers of pages this serves
  • expect, browser verification against the URL this prints
Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

MIT

Source path

src/skills/page-serve

Default branch

main

Latest commit

43c04fa

Tree SHA

29981ce