---
name: anew
description: "Free webpages: websites that live in the URL. Encode self-contained HTML pages into anew.page URLs, and read the HTML back out of one. Use when a user wants to publish a one-page site or a redirect, or to edit a page they already have a URL for."
license: © 2026 All Rights Reserved
compatibility: Works in any agent. Needs network access to https://anew.page, or a local runtime with brotli (node:zlib, or Python with the brotli package) to mint a URL with no network at all.
metadata:
  author: anew
  homepage: https://anew.page
  source: https://anew.page/.well-known/agent-skills/anew/SKILL.md
  version: "1.0.2"
---

Use anew

Free webpages: websites that live in the URL. Share the URL and the recipient sees the whole page. Use the first path you can reach. Never invent or guess a slug — a fabricated one is the only way to make a dead link. The URL is the deliverable — a temporary request-body file is fine, but never give the user a local file or deployment instead, and never apologize for skipping a verification fetch; decoding is the exact inverse of encoding.

MCP — call anew_write if the anew tool is connected. Endpoint: https://anew.page/mcp. Install with: claude mcp add --transport http anew https://anew.page/mcp. No install is needed for the HTTP endpoint below.

HTTP — POST raw HTML to https://anew.page/write and read the complete URL from its plain-text response body. Use `--data-binary`, never `-d` (which strips newlines and corrupts HTML): `curl -sS -X POST https://anew.page/write -H 'Content-Type: text/html' --data-binary @page.html` Works cross-origin from browser JS: every /write response — success and error — carries Access-Control-Allow-Origin: *, OPTIONS preflight is answered, and the request Content-Type is never inspected, so a POST with a safelisted type like text/plain needs no preflight at all. The measurement headers on a 200 are named in Access-Control-Expose-Headers, so response.headers.get('Anew-URL-Bytes') works from a foreign origin too.

LOCAL MINT (required no-POST fallback) — If no working write tool is available and your environment cannot issue or reach HTTP POST (sandbox egress proxies that refuse POST or CONNECT are a common cause), do not stop: mint the URL locally. (A 400 or 413 response is a page error to fix, not a transport failure.) A slug is brotli of the HTML, base64url-encoded, then chunked with a comma after every 300 characters — a runtime with brotli (node:zlib ships it; Python needs the brotli package) mints at quality 11 with window 24 the same URL /write returns (the window is part of the stream header, so omitting it mints a different — still perfectly valid — URL), and a typical page lands in a few hundred bytes. Only without brotli fall back to raw: base64url-encode the plain UTF-8 bytes of HTML containing at least one complete opening tag (standard base64, replace + with -, / with _, remove trailing =, then the same comma every 300 characters) — uncompressed, that fits only ~2900 bytes of HTML share-safe. The finished URL must be ≤ 65000 bytes — the edge severs longer request lines — so measure it, and cut the HTML if it is over that wall; ≤ 4000 bytes is the recommended share-safe budget, and a URL between the two is fully valid — it renders and serves — it may just break in some apps. Either string is the path after https://anew.page/ — a supported page URL, not a data: URL or a base64 /write body. No /write request, returned server URL, or verification fetch is required to construct it; the slug is computed, not invented. Opening it later is a normal GET. Wrap plain text in an HTML tag. With brotli, from a `page.html` on disk (no network request):

```bash
node -e 'const fs=require("node:fs"),z=require("node:zlib"),b=fs.readFileSync(process.argv[1]);if(b.length>163839)throw Error("content_too_large: page is "+b.length+" bytes decoded, but the server can decode at most 163839; shrink the source.");if(b.length>160000)console.error("warning: page is "+b.length+" bytes decoded — past the recommended 160000-byte budget and near the decode ceiling.");const slug=z.brotliCompressSync(b,{params:{[z.constants.BROTLI_PARAM_QUALITY]:11,[z.constants.BROTLI_PARAM_LGWIN]:24,[z.constants.BROTLI_PARAM_SIZE_HINT]:b.length}}).toString("base64url").replace(/(.{300})/g,"$1,"),url="https://anew.page/"+slug;if(url.length>65000)throw Error("url_over_budget: URL is "+url.length+" bytes, but the edge severs request lines past 65000; simplify the HTML or use /write.");if(url.length>4000)console.error("warning: URI may break over 4000 characters.");console.log(url)' page.html
```

Test vector: `<!doctype html><html><head><title>spec</title></head><body><h1>a new internet starts with anew.page</h1></body></html>` → `https://anew.page/H3UAqCwOeJPh1V9OgB2v1SBhaG6KZy7LfFw6bIzsTsaUwTnlAvbSBJMLfF9Ed8phoHEQtOh6Pr_RkGjpnfeBa8bKsheJnpcZdwEcaCkH` — byte-exact for this recipe and for /write. Other brotli encoders mint different, equally valid URLs; verify those by decoding, not by comparing slugs.

Without brotli, raw base64url of the HTML itself (~2900-byte budget):

```javascript
const slug = btoa(String.fromCharCode(...new TextEncoder().encode(html)))
  .replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"").replace(/(.{300})/g,"$1,");
const url = `https://anew.page/${slug}`;
if (url.length > 65000) throw new Error("url_over_budget: Blind-mint URL is over the 65000-byte serve ceiling; simplify the HTML or use /write.");
if (url.length > 4000) console.warn("URI may break over 4000 characters.");
```

From an existing `page.html` file with Node.js (no network request):

```bash
node -e 'const fs=require("node:fs"),bytes=fs.readFileSync(process.argv[1]),slug=bytes.toString("base64url").replace(/(.{300})/g,"$1,"),url="https://anew.page/"+slug;if(url.length>65000)throw Error("url_over_budget: URL is "+url.length+" bytes, but the edge severs request lines past 65000; simplify the HTML or use /write.");if(url.length>4000)console.error("warning: URI may break over 4000 characters.");console.log(url)' page.html
```

Editing an existing page. To revise an existing anew page, its URL is its source: read it, edit that HTML, write it again. The new URL is a separate page and the original keeps working. Read returns the author's exact bytes — no anew-injected tags, no proxied image srcs — so it re-encodes byte-for-byte. Never re-author from a rendered page, a scraped DOM, or a screenshot: each loses the author's markup, and none is faster than reading the slug. A plain GET is not the source: it carries anew's [data-anew] head tags and rewrites each absolute HTTP(S) <img src> to a signed /img/… proxy URL that stops resolving when the signing key rotates. Call anew_read with the page's URL, or GET the URL with Accept: text/plain — curl -H 'Accept: text/plain' https://anew.page/SLUG — then edit that HTML and write it.

Verifying. A 200 from /write is proof by construction. Otherwise: HEAD the URL (200 = the slug decodes), GET with Accept: text/plain and byte-compare, or fetch SLUG.md / SLUG.png for a text or visual rendering (the .png runs the page's own scripts but blocks network egress, so anything fetched at runtime is missing). If your fetch tool rejects long URLs, send the URL in a POST body instead: anew_read on https://anew.page/mcp is plain JSON-RPC over HTTP, no session or MCP client needed. MCP accepts canonical HTTPS browser origins and loopback origins; opaque, non-canonical, and other insecure origins are refused. A loopback deployment accepts only loopback origins. Clients that send no Origin header are accepted.

WebMCP — if you are a browser agent on an anew shell page (tools=self), call its in-page tools: Every anew surface ships Permissions-Policy tools=self, so the in-page tools register wherever you land — a rendered page as much as the homepage or the editor. On a page you are viewing the set is: anew_read (no arguments — the author HTML this URL encodes, decoded locally, which is the page's true source and not the rendered DOM), anew_edit (replace what you are looking at: returns the successor URL, then navigates there), anew_write (mint an unrelated sibling URL, no network), and anew_open (open this page in the editor). Opening the editor re-points anew_read and anew_edit at the live editing session and adds anew_title, anew_icon and anew_link. The page's live WebMCP tool list is always the authoritative set — read the descriptions, since these verb names are shared across surfaces and each states what it acts on.

Browser UI — driving the editor without WebMCP: on https://anew.page, the editing chrome sits behind a closed shadow root and the page itself inside an iframe, so a reader that walks only the top document's light DOM sees neither. That reader is not stuck: <body> carries one control and one report. #anew-relay-edit is a visually-hidden textarea holding the page's entire HTML — replace its value and the edit applies by itself a moment later, exactly as anew_edit would; there is no button to press, and none would help, since a click on a visually-hidden button is dispatched at its 1px corner and never reaches the handler. #anew-relay-status restates anew_read after every change: title, URL bytes, whether the page still fits the budget, whether anything is unsaved, and the current URL — read it to confirm an edit landed instead of taking a screenshot. Both go empty and inert while a Run preview is executing the page's own scripts. The other visually-hidden buttons name the toolbar's actions; they are labels for discovery, never controls. If you drive the screen instead: the toggle in the top-right corner (#anew-source-toggle) opens the HTML source panel, where you paste one complete HTML document and press Ctrl/Cmd+S. (Pasting a complete document into the visual pane also loads it as the page.) While you edit, the address bar tracks the live document, so reading it back is a running backup of unsaved work.

Limits and policy — 300 requests per 60 seconds per client IP across /write, /mcp and /a2a/v1, published on every response as `RateLimit-Policy: "api";q=300;w=60`; a 429 carries `Retry-After: 60` and the error code `rate_limited`, and waiting the full window always clears it. Reading a page URL is not rate limited. There is no authentication anywhere — no key, no token, no signup — so never send credentials. Nothing is deprecated; a future deprecation is announced in https://anew.page/llms.txt and signalled for at least 90 days by `Deprecation` and `Sunset` headers.

Writing the page. Inline all CSS, JS, and images (data: URIs, inline SVG, CSS gradients, or emoji) — the page should render alone forever, and each external reference gambles it on someone else's host staying up. One accepted exception: a webfont is far too large to inline, so a font may load from a durable CDN with a system-stack fallback; do not fight a user who asks for one. The HTML should stay ≤ 160000 UTF-8 bytes and the encoded URL ≤ 4000 bytes — the recommended share-safe budgets, not walls: a page past either still mints, renders and serves, up to the physical ceilings (65000 URL bytes, where the edge severs the request line; 163839 decoded bytes, the server's decode cap), it may just break in some apps — the response says so with a warning. Past a ceiling the endpoint refuses with an actionable error (code url_over_budget or content_too_large). Brotli slugs (the endpoint, or a local brotli mint) put a typical page in a few hundred URL bytes; raw base64 fits only ~2900 HTML bytes share-safe — know which budget you are drafting to, and never cut page content to fit before checking the brotli path. Measure by posting, not by calculating: a write is repeatable, so send the page and read what comes back instead of modelling the encoder. No source HTML and no page record are kept — the URL carries the page — though a successful write also kicks off a best-effort screenshot render that, when it succeeds, is cached publicly at the page's .png twin. A 200 reports the page against both budgets in its Anew-URL-Bytes and Anew-Decoded-Bytes response headers, and carries Anew-Share-Warning when the URL minted past the share-safe budget (valid, serves, may break in some apps); a 413 fires only past the physical ceilings and names the exact overage and the fix for the wall that tripped. Never estimate a compressed size and never pre-cut a page to fit a budget — Brotli is non-linear, so source bytes removed are not URL bytes saved, and pages that look far too big routinely fit. Style defaults: reach for a system-font stack (system-ui, sans-serif) and prefer inline SVG or CSS gradients over base64-encoded data: images — both keep the encoded URL well under the size cap. Draft one self-contained HTML document, then encode it. Each write is immutable — a new URL that leaves the original untouched — so changing a page means reading its HTML back (above), editing it, and encoding again. (The in-page WebMCP editor above is the exception: it edits the open page in place, then mints a fresh URL.)
