---
name: static-html-site-publishing
description: Use when the user wants one or more local HTML files published as browsable web pages, either locally, on a LAN, or via a temporary/public static deployment.
version: 1.1.1
author: Hermes Agent
license: MIT
metadata:
  hermes:
    tags: [html, static-site, publishing, cloudflare, local-preview, shared-drive]
    related_skills: [cloudflare-deploy, messaging-platform-file-delivery]
---

# Static HTML site publishing

## Overview

Use this skill when a user has one or more existing `.html` files and wants them turned into something that opens cleanly in a browser.

The key distinction is whether the source directory is writable. In shared drives, NAS mounts, synced folders, or externally managed project folders, the agent may be able to read files but not create helper files next to them. In that case, stage a deployable copy in a writable local directory, add an index page there, and publish from the staged copy rather than mutating the source folder.

## When to use

Use this when the user asks to:
- deploy existing HTML files
- make a folder of HTML files browsable
- generate a local preview URL or a public URL for static pages
- publish design prototypes, dashboard mocks, or standalone HTML artifacts

Do not use this for:
- frameworks that need a build pipeline (React/Vite/Next/etc.)
- backend apps that require server logic
- Office/PDF file delivery tasks

## Default workflow

1. **Inventory the source files**
   - Confirm how many HTML files exist and whether they appear standalone or have sibling assets.
   - Completion criteria: you know the entry files and whether CSS/JS/images must travel with them.

2. **Check whether the source directory is writable**
   - If writable, you may add `index.html` in place.
   - If not writable, create a local staging directory and copy the needed files there first.
   - Completion criteria: you have a writable directory that contains the deployable site.

3. **Create a human-friendly entry page**
   - When there are multiple HTML files, add an `index.html` that links to each page with clear labels.
   - Keep filenames untouched unless the user asked for renaming.
   - Completion criteria: opening `/` presents a usable landing page.

4. **Start a local static server and verify it**
   - Use a simple static server such as `python -m http.server` against the deployable directory.
   - Verify `/` and each target HTML page return successfully over HTTP.
   - Completion criteria: local browserable URLs work, not just file paths.

5. **Set the retention window for temporary shares**
   - Default temporary-public expiry to **15 days** when the user does not specify a duration.
   - Allow the user to choose any expiry from **3 to 90 days**.
   - If the user asks for less than 3 days or more than 90 days, do not silently accept it; clamp only with explicit user confirmation or ask them to pick a value inside the supported range.
   - Record the exact expiry timestamp that will drive cleanup.
   - Completion criteria: the deployment has an explicit expiry window and exact expiry time before it is published.

6. **Choose the publication target**
   - Local only: keep the local server URL.
   - LAN: bind to an accessible host/interface and provide the reachable URL.
   - Public temporary share: prefer a reversible, low-friction static host or tunnel.
   - If a canonical service domain already exists (for example `https://hermesadmin.bremen.com.tw/`), prefer that formal domain over temporary third-party preview hosts.
   - Public longer-lived share: prefer a real static deployment or a path-based publish under the user's existing formal domain.
   - For temporary-public shares, pair the publish step with a one-shot cleanup job that removes both the staged site and the public route when the expiry time is reached.
   - Completion criteria: the user receives a URL appropriate to the requested audience, domain preference, and retention policy.

7. **Verify the public result and communicate expiry**
   - Fetch the public URL and at least one leaf page after deployment.
   - If verification from one path is blocked by environment quirks, verify with another available path and state the limitation plainly.
   - Completion criteria: you have real evidence the published URL is alive.

## Read-only source staging pattern

When the source folder is read-only:

1. Create a writable staging directory such as `~/site-deploy/<project>/`.
2. Copy only the required HTML/assets into staging.
3. Add `index.html` in staging, not in the source.
4. Serve and publish from staging.

This avoids permission failures and keeps shared-drive source material pristine.

See `references/read-only-shared-drive-staging.md` for a concrete pattern.

## Cloudflare temporary-public pattern

When the user wants a quick public URL and Cloudflare auth is not already configured:

1. Prepare a minimal static-assets deployment directory.
2. Add a tiny Worker entry that forwards requests to static assets.
3. Use `wrangler deploy --temporary` to obtain a temporary preview deployment and public `workers.dev` URL.
4. Default the temporary share to a **15-day** retention window unless the user specifies another duration.
5. Accept only **3 to 90 days** for user-defined temporary retention.
6. Return both the preview URL and the claim URL if Wrangler emits one, and explicitly tell the user the exact expiry date/time.
7. Clearly label it as temporary and recommend promotion to a user-owned Pages/Workers project for long-term use.

This is often more reliable than ad-hoc tunnels when the goal is simply "make these static HTML files public now."

## Formal-domain path publishing

When the machine already has a canonical public domain and tunnel/reverse-proxy infrastructure, prefer publishing under that domain instead of handing out a temporary `workers.dev` or `trycloudflare.com` hostname.

Recommended pattern:
1. Stage the HTML bundle under a writable local deploy root.
2. Serve it from a dedicated local static port.
3. Add a path-specific ingress or reverse-proxy rule so only that prefix maps to the static port.
4. Reload the managed public-edge service.
5. Verify the public HTTPS URL plus the primary leaf pages.
6. If the user asks for expiry, schedule a one-shot cleanup that removes both the staged site and the ingress rule.

See `references/hermesadmin-formal-public-paths.md` for the validated Bremen-domain example.

## Common pitfalls

1. **Trying to write helper files into a read-only shared drive**
   - Symptom: write/create fails even though reads work.
   - Fix: stage a writable copy locally, then publish from the copy.

2. **Returning only local filesystem paths**
   - Symptom: user gets `/Users/.../index.html` and still cannot open it remotely.
   - Fix: always provide an HTTP URL, local or public.

3. **Treating a folder of multiple HTML files as a single-page deploy**
   - Symptom: the user can open one page but has no clear index.
   - Fix: create an `index.html` landing page that links to each artifact.

4. **Using a tunnel as if it were durable hosting**
   - Symptom: the URL dies when the process stops.
   - Fix: label tunnels as temporary; for stable sharing, deploy to a user-owned static host.

5. **Publishing without verifying leaf pages**
   - Symptom: homepage works but one of the main HTML files 404s or redirects oddly.
   - Fix: verify `/` plus each primary page after deployment.

## Verification checklist

- [ ] Source HTML files identified
- [ ] Writable deploy directory confirmed
- [ ] `index.html` present when multiple pages exist
- [ ] Local HTTP preview tested
- [ ] Temporary-public retention window set explicitly (default 15 days, user-defined 3-90 days)
- [ ] Public/LAN URL produced when requested
- [ ] Homepage verified over HTTP
- [ ] Each primary HTML page verified over HTTP
- [ ] User informed whether the share is temporary or long-lived
- [ ] User shown the exact expiry date/time for temporary shares
