$ htmlup

htmlup

Share your generated reports with one command.

Point it at an HTML file — like a report your AI assistant just wrote — and get back a public URL you can send to anyone. Nothing to host, no secrets stored. Free and open source.

# Install

Install with Homebrew on macOS or Linux. Or grab a prebuilt binary or archive from the releases page.

Homebrew
brew tap truehhart/tap
brew trust truehhart/tap   # one-time: Homebrew 6+ requires trusting non-official taps
brew install --cask htmlup

# Usage

The shape is always htmlup publish <provider> <path>. Point it at a single .html file or a directory of static assets — directories upload recursively, preserving structure. On success it prints a public URL per file and exits.

GitHub Pages
# branch & dir auto-detected from the repo's Pages settings
htmlup publish github ./claude-html-reports --repo truehhart/share

# manual targeting (skips auto-detect); preview with --dry-run
htmlup publish github ./claude-html-reports --repo truehhart/share \
  --branch gh-pages --dir reports --dry-run
S3 (exposed via CloudFront)
# upload objects to a bucket
htmlup publish s3 ./site --bucket my-bucket

# with key prefix and explicit region
htmlup publish s3 ./site --bucket my-bucket \
  --prefix path/ --region us-east-1
Global flags (every provider)
--dry-run      # enumerate what would upload + the resulting URLs; no writes
-v, --verbose  # per-file progress and SDK-level detail

# Two backends

Backends are pluggable behind one Provider interface — adding a target is one new package plus registration, no edits to the publish flow.

GitHub Pages github

Commits your file set to the target branch via the Git Data API, creates the branch if missing, and flips Pages on if it isn't already. Auto-detects where Pages serves from and reads a CNAME (if present) to report the custom-domain URL. You get a public URL back for every file.

S3 s3

One PutObject per file with content-type inferred from the extension. No bucket-policy or website-config mutation — you own public exposure, expected via CloudFront in front of the bucket.

# Stateless by design

htmlup is single-purpose and boring on purpose. No daemon, no local database, no tracking of what was published.

uploads & exits

No lifecycle management. Every invocation publishes and quits. (GitHub Pages expiry, if you want it, is an opt-in cron Action you copy into the target repo — never run by the CLI.)

never stores credentials

htmlup never reads, prompts for, or caches secrets. Each official SDK owns its own credential resolution.

pluggable backends

Every target implements one interface and self-registers. Contributors add a backend without touching core code.

thin commands

Cobra commands parse flags and delegate; the real logic lives in provider packages and tested pure helpers.

# Password-protect a page

Pass --password and every .html is sealed into a self-decrypting page before it leaves your machine. No accounts, no link expiry, no server in the loop.

Publish encrypted
# prompt for the password, no echo
htmlup publish github ./reports --repo truehhart/share --password -

# or supply it via the environment
HTMLUP_PASSWORD=hunter2 htmlup publish s3 ./reports --bucket my-bucket

The decryptor is plain JavaScript baked into the page — nothing to install for whoever opens the link. Here's a real one, htmlup-encrypted; the password is hunter2:

mystery.html — sealed with --password

# Authentication

Auth is delegated entirely to the official SDKs' standard credential chains. htmlup holds nothing.

GitHub — token resolution order
# 1. $GITHUB_TOKEN  → 2. $GH_TOKEN  → 3. token from the gh CLI
gh auth login   # missing token? actionable error points you here
AWS — default credential chain
# env vars → ~/.aws/credentials → SSO → role / instance creds
# --region only overrides the resolved region

# Also a Claude Code plugin

This repo doubles as a Claude Code plugin marketplace. It publishes the htmlup skill, which teaches Claude how to drive the CLI.

In Claude Code
/plugin marketplace add truehhart/htmlup
/plugin install htmlup@htmlup