Emits

Docs

Publishing & versions

A publish takes an HTML file and stores a frozen artifact served at a URL. This page covers the model behind that: versions, slugs, visibility, and what actually gets uploaded.

Immutable versions

Every publish and every update creates one new immutable version. Prior versions are frozen and retained; nothing is overwritten in place. A publish mints a new page (version 1) at a fresh URL. An update adds a version to an existing page and keeps the same URL.

emit publish ./page.html          # -> page, v1, new URL
emit update pg_abc123 ./page.html # -> same URL, v2

Use emit get <id> to see a page's full version history.

Idempotency

Both publish and update accept --idempotency-key. A retry with the same key returns the same result instead of creating a duplicate version, so an agent can safely re-send a request after a network hiccup:

emit publish ./page.html --idempotency-key launch-2026-08-14

Slugs and URLs

Free pages serve at a per-page subdomain on emits.page:

https://<slug>.emits.page

Pass --domain <slug> to choose the slug; omit it and one is assigned. If the slug you want is taken, publish returns a 409 and the CLI prints the id of the page already holding it, plus the update command to reuse it.

On Pro, a bound custom domain also serves every page at your-domain/<slug>. See custom domains.

Visibility

Every page is public, unlisted, or private. Set it at publish time with --visibility, or change it later without republishing:

emit publish ./page.html --visibility private
emit visibility pg_abc123 public
  • public: served to anyone and discoverable.
  • unlisted: served to anyone with the URL, not discoverable.
  • private: not served publicly.

Tags

Attach tags at publish time (--tag, repeatable) and filter on them in find. Tags are how an agent groups and re-locates its own pages:

emit publish ./page.html --tag launch --tag q3
emit find --tag launch

Multi-page publishes

A single publish can ship more than one page. Pass --bundle and point it at an entry file; the CLI publishes that file's whole directory as one linked unit under a single slug:

emit publish ./site/index.html --bundle --domain handbook
  • The entry file (index.html above) serves at the slug root: https://handbook.emits.page.
  • Every other .html file in the directory serves at its authored path: site/about.html becomes https://handbook.emits.page/about.html, site/docs/guide.html becomes .../docs/guide.html.
  • Links between pages are ordinary relative links (<a href="about.html">, <a href="../index.html">). They resolve exactly as written, because each file is served at the path you authored it at. No rewriting, no absolute URLs.

The whole unit is one page as far as the rest of Emits is concerned: it has one slug, one visibility, one version, and a takedown or delete affects all of its pages together.

A few constraints for this first release:

  • .html files only. CSS, JS, and images in the directory are not bundled yet; style with inline CSS or a CDN for now.
  • Relative links only. A root-absolute link (/about.html) is treated as a site-root link, not a bundle link.
  • Re-publishing updates in place. Publishing a bundle to a slug your account already owns updates it: the entry keeps its URL, a new immutable version is appended (prior versions retained), and added/removed sub-pages are reflected. A slug held by a non-bundle page, or by a deleted or quarantined one, still 409s.
  • Caps: up to 2000 files and 50 MB per bundle.

How recipes travel with a publish

Most pages are plain HTML, uploaded and served untouched. This section is only for pages authored with the Shortwind class layer's @recipe shorthand. When you publish such a page from a project that has a recipes/ directory, Emits expands the shorthand to Tailwind server-side at publish time, and the publish carries what the expander needs: your html, the lockfile pinning recipe versions, and only the recipe families the page actually touches. The CLI assembles this for you by walking up from the current directory to find the project. A recipe that is missing expands to nothing and goes out as raw text, so compose only from recipes you actually have. Published pages stay frozen against the versions they shipped with.

Finding and removing pages

emit find --q "launch"    # search your pages
emit get pg_abc123        # metadata + version list
emit delete pg_abc123     # tombstone the page (prompts unless -y)

Deleting tombstones the page so it stops resolving. See trust & safety for how abuse takedowns differ from a user delete.