diff --git a/README.md b/README.md
index d179968..c94a232 100644
--- a/README.md
+++ b/README.md
@@ -35,6 +35,21 @@ tot notes.md
| `tot remove ` | Remove the living page from its share link. |
| `tot login --key ` | Optional. Publish as an owned account instead of anonymous. |
+## For AI agents
+
+> [!NOTE]
+> The skill works without the `tot` CLI: it publishes via curl against the HTTP API at
+> `https://api.tot.page`. With `tot` on PATH it uses the CLI instead.
+
+### Install
+
+```bash
+npx skills add plannotator/tot
+```
+
+Skill: [`skills/tot/SKILL.md`](skills/tot/SKILL.md) — publish, update, remove, HTML
+assets, ownership. Plain API reference: [site/agents.md](site/agents.md).
+
## How it works
Files are served byte for byte. Markdown comes back as raw markdown. HTML comes back as raw HTML.
diff --git a/docs/REPO_LAYOUT.md b/docs/REPO_LAYOUT.md
index b24a271..9252de8 100644
--- a/docs/REPO_LAYOUT.md
+++ b/docs/REPO_LAYOUT.md
@@ -14,6 +14,8 @@ Root is for the npm package and top-level project files:
- `src/` - CLI implementation.
- `test/` - CLI tests.
+- `skills/tot` - distributable agent skill (`SKILL.md` + `references/`) that teaches
+ agents to publish via the `tot` CLI or the HTTP API directly, no install required.
- `package.json`, `pnpm-lock.yaml`, `tsconfig*.json`, `vitest.config.ts` - package tooling.
- `README.md`, `LICENSE` - public package metadata.
diff --git a/skills/tot/SKILL.md b/skills/tot/SKILL.md
new file mode 100644
index 0000000..00b55da
--- /dev/null
+++ b/skills/tot/SKILL.md
@@ -0,0 +1,80 @@
+---
+name: tot
+description: >-
+ Publish a markdown or HTML file to a live public tot.page URL — a living link
+ plus immutable @hash snapshots — then update or remove it, with curl alone or
+ via the tot CLI. Use when asked to publish, share, host, or put online a
+ document, report, or page, to update or delete an existing tot.page link, or
+ whenever tot or tot.page comes up.
+---
+
+# tot — publish a file to a live link
+
+One local file becomes one public URL. No signup, no install — `curl` is enough
+(the `tot` CLI, when present, makes the same calls for you). Files are served
+raw: markdown comes back as raw `.md`, HTML as raw `.html`, byte for byte. No
+config, no build step.
+
+Every page has two URLs:
+
+- **living** — `https://tot.page/{slug}`, always shows the latest version.
+- **frozen** — `…/{path}@{hash}`, one immutable snapshot per publish, for
+ pointing at "exactly this version".
+
+## The rules that bite
+
+- **Checkpoint gate.** A fresh page answers `version: null` until its first git
+ checkpoint lands (~2–10s). Poll the read endpoint until `version` is
+ non-null — the link 404s until then. A publish is done when the poll passes,
+ not when the POST returns.
+- **Open pages.** Without an API key every page is open: anyone holding the link
+ can read, update, or delete it. Publish content you mean to be public, and
+ treat each link as the credential it is.
+- **1.5 MB body limit** (UTF-8) — over it the API answers `422`. Errors are
+ JSON: `{"error":{"code":"…","message":"…"}}`.
+
+## Route: CLI or curl
+
+```bash
+command -v tot
+```
+
+- **found** → use the CLI; it scans HTML assets, waits out the checkpoint, and
+ tracks published pages in `~/.tot` across sessions:
+ `tot ` publish · `tot update ` · `tot remove ` · `tot list`
+- **not found** → the curl flows below; identical capability, zero install.
+
+## Publish (markdown, or HTML with no local refs)
+
+```bash
+BODY=$(jq -Rs '{kind: "markdown", body: .}' notes.md) # HTML → kind: "html"
+RESP=$(curl -sS -X POST https://api.tot.page/v1/documents \
+ -H 'content-type: application/json' -d "$BODY")
+WS=$(jq -r .workspace.id <<<"$RESP") # the page's identity — keep it
+DOC=$(jq -r .document.id <<<"$RESP") # for update/remove — keep it
+```
+
+`jq -Rs` JSON-encodes the file safely; hand-writing `body` breaks on newlines
+and quotes. HTML with local file references takes the asset flow instead — see
+Branches below.
+
+Pass the checkpoint gate, then report both URLs:
+
+```bash
+until PAGE=$(curl -sS "https://api.tot.page/v1/workspaces/$WS/documents/$DOC") \
+ && [ "$(jq -r .version <<<"$PAGE")" != "null" ]; do sleep 2; done
+jq -r '"living: \(.share_url)\nfrozen: \(.file_url)"' <<<"$PAGE"
+```
+
+Done when both URLs are in hand and given to the user. `$WS` and `$DOC` are the
+page's identity for every later update or remove — keep them for the session;
+across sessions, note them next to the source file, or switch to the CLI, which
+records them in `~/.tot`.
+
+## Branches
+
+- **HTML referencing local files** (images, stylesheets, scripts, video) —
+ upload assets before the document:
+ [references/html-assets.md](references/html-assets.md)
+- **Update · remove · key auth · full endpoint reference** —
+ [references/api.md](references/api.md)
diff --git a/skills/tot/references/api.md b/skills/tot/references/api.md
new file mode 100644
index 0000000..d7ffa8a
--- /dev/null
+++ b/skills/tot/references/api.md
@@ -0,0 +1,85 @@
+# tot.page API reference
+
+Base URL `https://api.tot.page`; pages are served at `https://tot.page/{slug}`.
+Auth is optional: send `Authorization: Bearer wsk_live_…` to publish as an owned
+account. Without it pages are open — the link is the key (see SKILL.md).
+
+Body limit 1.5 MB (UTF-8) → `422`. Errors are JSON:
+`{"error":{"code":"…","message":"…"}}`.
+
+## POST /v1/documents — publish (markdown, or HTML with no local refs)
+
+Request: `{"kind": "markdown" | "html", "body": "", "title"?: ""}`
+
+Response `201` — note the nesting; the document lives under `.document`:
+
+```json
+{
+ "document": {
+ "id": "doc_…",
+ "workspace_id": "ws_…",
+ "doc_path": "index.md",
+ "kind": "markdown",
+ "title": null,
+ "version": null,
+ "share_url": "https://tot.page/{slug}",
+ "file_url": null,
+ "created_at": "…",
+ "updated_at": "…"
+ },
+ "workspace": { "id": "ws_…", "slug": "…", "share_url": "…", "visibility": "open" }
+}
+```
+
+`version`/`file_url` are `null` until the first checkpoint lands (~2–10s); poll
+the read endpoint below until `version` is non-null.
+
+## GET /v1/workspaces/{wsId}/documents/{docId} — read
+
+Returns the document object **bare** (no `.document` wrapper):
+
+`id, workspace_id, doc_path, kind, title, version, share_url, file_url, body,
+created_at, updated_at`
+
+- `Accept: application/json` (default) → the object above.
+- `Accept: text/markdown` → the raw body.
+
+This is also the checkpoint poll.
+
+## PUT /v1/workspaces/{wsId}/documents/{docId} — update, same living link
+
+**Raw body, not JSON.**
+
+```bash
+curl -sS -X PUT "https://api.tot.page/v1/workspaces/$WS/documents/$DOC" \
+ -H 'content-type: text/markdown' --data-binary @notes.md
+```
+
+- Content-Type: `text/markdown` or `text/html`.
+- Optional `If-Match: ` → `412` when the page changed under you.
+- Returns the bare document with the new `version` and `file_url`. The living
+ `share_url` reflects the new version within ~60s.
+- HTML with local refs: upload new/changed assets first — see
+ [html-assets.md](html-assets.md).
+
+## DELETE /v1/workspaces/{wsId}/documents/{docId} — remove
+
+`204`, hard delete, no undo. The living link 404s immediately; frozen `@hash`
+snapshots stay up for the workspace's lifetime. Open pages: anyone with the
+link can delete.
+
+## Workspace endpoints — for HTML with assets
+
+- `POST /v1/workspaces` → `201` with the workspace **nested**:
+ `{"workspace": {"id": "ws_…", "slug": "…", "share_url": "…", "visibility": "open"}}`
+- `PUT /v1/workspaces/{wsId}/assets/{assetPath}` — raw asset bytes; 200.
+- `POST /v1/workspaces/{wsId}/documents` — request
+ `{"doc_path": "index.html", "kind": "html", "body": ""}`; `201` with the
+ bare document object.
+
+Full asset flow and scanning rules: [html-assets.md](html-assets.md).
+
+## GET /v1/me — identify a key
+
+`Authorization: Bearer wsk_live_…` → `{ "user_id": "…", "email": "…",
+"active_org_id": "…" }`. Use to verify a key before relying on it.
diff --git a/skills/tot/references/html-assets.md b/skills/tot/references/html-assets.md
new file mode 100644
index 0000000..eace8c8
--- /dev/null
+++ b/skills/tot/references/html-assets.md
@@ -0,0 +1,59 @@
+# HTML with local assets
+
+For HTML that directly references local files. Bare HTML (only external URLs or
+inline content) takes the simple flow in SKILL.md instead.
+
+## Scan the HTML first
+
+Direct refs that count as assets:
+
+- ``, `` entries, `