Skip to content

Agent Skill

A portable Agent Skill teaches MCP clients how to publish self-contained HTML to a stable share link, update the same link, pull optional page feedback, and style with built-in themes. It is markdown + judgement only — thin MCP wiring, no shell scripts, curl wrappers, or binary downloads.

MCP endpoint: https://app.artifactpublisher.com/mcp (streamable HTTP)
Full MCP reference: MCP integration

Until an official registry publish is available, install by copying the skill text from this page (or the in-repo tree skills/artifact-publisher/ if you already have a checkout).

Do not claim a public npx skills add install path until that publish is live.

Place a folder like this in your client’s skills directory:

artifact-publisher/
SKILL.md
references/
publish-ops.md
desk-admin.md
failures.md

Copy the bodies below into those files. Then wire the hosted MCP once (see Connect).

  1. After publish_artifact / update_artifact, report artifact.url (control-origin share/viewer) first. Use artifact.viewer_url when a version pin helps. Never make the raw artifact-origin URL the primary share link.
  2. Never print, paste, commit, or write into artifacts: ar_pk_…, ar_oat_…, ar_ort_…, ar_oac_…, refresh tokens, cookies, or Authorization headers. Prefer OAuth or env ARTIFACT_PUBLISHER_KEY.
  3. Do not invent HTML when a real file exists — read the file and pass its contents to publish_artifact / update_artifact.
  4. Call get_authoring_guide before large styling; prefer <meta name="ap-theme" content="firn">.
  5. Feedback is optional/secondary. get_feedback is pull-only — do not frame the product as an approval loop.
  6. Thin MCP wiring only — no shell scripts, no curl wrappers, no reckless exec, no downloading or running arbitrary binaries.
  1. Open Your dashboard and mint a publisher key (shown once). Store it in the client secret store or env — never echo it in chat.
  2. OAuth (preferred when the client supports browser consent): production has OAuth mode on. Register https://app.artifactpublisher.com/mcp, complete consent in the browser; never ask the user to paste an access token into chat.
  3. Key (practical for Hermes / OpenClaw headless / always-on): set ARTIFACT_PUBLISHER_KEY and send Authorization: Bearer ${ARTIFACT_PUBLISHER_KEY}.
  4. Keyless initialize / tools/list / ping work for discovery only.

Claude Code (prefer env-backed header):

Terminal window
claude mcp add --transport http artifact-publisher https://app.artifactpublisher.com/mcp \
--header "Authorization: Bearer ${ARTIFACT_PUBLISHER_KEY}"

Cursor / Codex / similar (mcpServers):

{
"mcpServers": {
"artifact-publisher": {
"url": "https://app.artifactpublisher.com/mcp",
"headers": {
"Authorization": "Bearer ${env:ARTIFACT_PUBLISHER_KEY}"
}
}
}
}

(Some clients use ${ARTIFACT_PUBLISHER_KEY} without env: — match your client.)

More client tabs: Quickstart.

Only these names exist on the live surface today (tools/list):

publish_artifact, update_artifact, set_artifact_access, get_feedback, reply_to_feedback, list_artifacts, revoke_artifact, configure_workspace, get_artifact_board, reset_artifact_board, get_artifact_state, set_artifact_state, reset_artifact_state, get_authoring_guide.

(get_artifact_board / reset_artifact_board are deprecated aliases — prefer the state tools.)

Details: MCP tools.

  1. Read existing HTML if a file exists; else author self-contained HTML (inline assets; sandbox has no network).
  2. Optional: get_authoring_guide + ap-theme firn before large CSS.
  3. publish_artifact → report artifact.url first.
  4. Later: update_artifact (same link), optional get_feedback / reply_to_feedback, set_artifact_access, or revoke_artifact.

The canonical private source is skills/artifact-publisher/ in the product repo. The publishable files are reproduced here for install without a private clone.

---
name: artifact-publisher
description: Publish self-contained HTML to a stable share link and read page feedback via Artifact Publisher MCP. Use when the user wants a review/share URL for agent-made HTML, to update the same link, change access, pull comments, or style with built-in themes. Do not use for unrelated hosting, SPA/multi-file deploys, or package registries.
version: 0.1.0
author: Angle Labs GmbH
license: MIT-0
platforms: [macos, linux, windows]
required_environment_variables:
- name: ARTIFACT_PUBLISHER_KEY
optional: true
prompt: "Publisher key for headless/always-on agents (Hermes, OpenClaw operators). Mint once at https://artifactpublisher.com/account/ — shown once; never paste into chat. Prefer OAuth browser consent when the client supports it."
metadata:
tags: [html, publishing, sharing, share-link, mcp, feedback, review]
hermes:
tags: [html, publishing, sharing, mcp, feedback]
homepage: https://artifactpublisher.com
openclaw:
emoji: 📎
homepage: https://artifactpublisher.com
primaryEnv: ARTIFACT_PUBLISHER_KEY
requires:
env:
- ARTIFACT_PUBLISHER_KEY
envVars:
- name: ARTIFACT_PUBLISHER_KEY
required: true
description: Scoped publisher key (Bearer). Prefer OAuth when the client supports browser consent; for headless/always-on agents this env var is the practical path. Mint at https://artifactpublisher.com/account/ — never commit or paste into chat.
---
# Artifact Publisher
Hosted MCP server that turns one self-contained HTML document into a stable,
unlisted share link. Reviewers open it without an AI-vendor account; optional
page comments come back to the agent with `get_feedback`. MCP-first and
provider-agnostic. Free plan available.
**Server:** `artifact-publisher` · version `0.1.0`
**Endpoint:** `https://app.artifactpublisher.com/mcp` (streamable HTTP)
**Docs:** https://artifactpublisher.com/docs/mcp/
## Hard rules
1. After `publish_artifact` / `update_artifact`, report **`artifact.url`**
(control-origin share/viewer) **first**. Use `artifact.viewer_url` when a
version pin helps. **Never** make the raw artifact-origin URL the primary
share link.
2. **Never** print, paste, commit, or write into artifacts: `ar_pk_…`,
`ar_oat_…`, `ar_ort_…`, `ar_oac_…`, refresh tokens, cookies, or
`Authorization` headers. Prefer OAuth or env `ARTIFACT_PUBLISHER_KEY`.
3. Do **not** invent HTML when a real file exists — read the file and pass its
contents to `publish_artifact` / `update_artifact`.
4. Call `get_authoring_guide` before large styling; prefer
`<meta name="ap-theme" content="firn">`.
5. Feedback is optional/secondary. `get_feedback` is **pull-only** — do not
frame the product as an approval loop.
6. **Thin MCP wiring only** — no shell scripts, no curl wrappers, no reckless
`exec`, no downloading or running arbitrary binaries.
## Route the request
| Route | When | Load |
| --- | --- | --- |
| Publish / update / access / feedback / state / authoring | Publish HTML, refresh a link, read/reply to feedback, themes, shared state | [publish-ops](references/publish-ops.md) |
| Desk / keys / account links | User asks to sign in, mint/revoke keys, or connect MCP from the desk | [desk-admin](references/desk-admin.md) |
| Failures | Auth, size, quota, or consent problems | [failures](references/failures.md) only after a failure |
## Setup
Wire the hosted MCP once. This skill is markdown + judgement only; it does not
ship binaries.
### 1. Credential
1. Open https://artifactpublisher.com/account/ and mint a publisher key (shown
once). Store it in the client secret store or env — **never echo it in chat**.
2. **OAuth (preferred when the client supports browser consent):** register
`https://app.artifactpublisher.com/mcp`, complete consent in the browser;
never ask the user to paste an access token into chat.
3. **Key (practical for Hermes / OpenClaw headless / always-on):** set
`ARTIFACT_PUBLISHER_KEY` and send `Authorization: Bearer ${ARTIFACT_PUBLISHER_KEY}`.
4. Keyless `initialize` / `tools/list` / `ping` work for discovery only.
### 2. Other MCP clients
See https://artifactpublisher.com/docs/ for Claude Code, Cursor, Codex, and
other client snippets. Prefer env-backed headers; never paste keys into chat.
### 3. Desk
Mint and manage keys at https://artifactpublisher.com/account/. Keys are shown
once; only a hash is stored server-side.
## Live tools (honesty)
Only these names exist on the live surface today
(`ARTIFACT_RELAY_TOOLS` / `tools/list`):
`publish_artifact`, `update_artifact`, `set_artifact_access`, `get_feedback`,
`reply_to_feedback`, `list_artifacts`, `revoke_artifact`, `configure_workspace`,
`get_artifact_board`, `reset_artifact_board`, `get_artifact_state`,
`set_artifact_state`, `reset_artifact_state`, `get_authoring_guide`.
(`get_artifact_board` / `reset_artifact_board` are deprecated aliases — prefer
the state tools.)
## Quick loop
1. Read existing HTML if a file exists; else author self-contained HTML (inline
assets; sandbox has no network).
2. Optional: `get_authoring_guide` + `ap-theme` firn before large CSS.
3. `publish_artifact` → report **`artifact.url` first**.
4. Later: `update_artifact` (same link), optional `get_feedback` /
`reply_to_feedback`, `set_artifact_access`, or `revoke_artifact`.
Details: [publish-ops](references/publish-ops.md).
# Publish operations
Use the connected Artifact Publisher MCP. Do not shell out, curl the endpoint,
or wrap tools in scripts.
## Publish
1. If a real HTML file exists on the machine, **read it** and pass the full
string as `html`. Do not invent a stub or paraphrase.
2. HTML must be self-contained: sandbox has **no network**, so inline CSS,
scripts, fonts, and images (e.g. data URIs). Plain links still open in a
new tab for the viewer.
3. Optional before large styling: `get_authoring_guide`. Prefer
`<meta name="ap-theme" content="firn">` in `<head>`.
4. Call `publish_artifact` with `html` and optional `title`, `summary`,
`expires_at`, `comments_enabled`, `visibility`, `allowed_emails`.
5. On success, report **`artifact.url` first** (control-origin share/viewer).
Add `artifact.viewer_url` when a version pin helps. Do **not** lead with the
raw artifact-origin document URL (iframe-only).
Default visibility is `public` (unlisted by link; not indexed). For coworkers
without accounts, use `public`, not `allowlist`.
Free plan (current product defaults): size ceiling on UTF-8 HTML (see tool
error / docs; typically 10 MiB), 5 active artifacts, 50 versions — treat live
tool errors as authoritative.
## Update (same link)
1. Call `update_artifact` with `artifact_id` (id, slug, or viewer URL) and
`expected_version` equal to the current version.
2. Pass new `html` for a new immutable version; the share link moves to it.
Earlier versions stay at pinned URLs.
3. Optional `title` renames; title-only (no `html`) renames without a new body
version (still counts toward some rate limits — see tool text).
4. Again report **`artifact.url` first**.
## Access without a new version
`set_artifact_access` — change `visibility` / `allowed_emails` without bumping
the HTML version.
| visibility | Who can open |
| --- | --- |
| `public` (default; `unlisted` alias) | Anyone with the link; no sign-in |
| `private` | Owner only (signed in) |
| `allowlist` | Signed-in users whose primary email is listed |
## Feedback (optional, secondary)
Not an approval workflow (share-first product).
- `get_feedback` — pull comments (oldest first). Filters: `unresolved_only`,
`since`, `version` (default current for `anchor_status`), page with `limit` /
`cursor`.
- `reply_to_feedback` — one reply per comment; optional `resolve: true`.
Second reply → conflict.
Selected-passage / quote-anchored comments may appear when the viewer supports
them; do not claim long-press or chat-native annotation UX.
## List / revoke
- `list_artifacts` — workspace artifacts, newest first, unresolved counts.
- `revoke_artifact` — stop serving (410); cannot undo. Confirm with the user.
## Shared state
Synced JSON key/value for page JS (`ArtifactRelayState`). Limits: 200 keys,
16 KiB/value, 64 KiB total.
- `get_artifact_state` / `set_artifact_state` / `reset_artifact_state`
- Deprecated: `get_artifact_board` / `reset_artifact_board` — prefer state tools
## Workspace defaults
`configure_workspace` — read/update allowed defaults (empty settings = read).
Platform guardrails are refused. Not available in every workspace.
## Authoring
`get_authoring_guide` — themes, `ap-*` layout classes, example, snippet, size
and sandbox rules. Optional `theme` (`firn`, `firn@1`) validated as selected.
## Non-goals
Multi-file / SPA hosting, DOM annotation bundles, local server
install/upgrade/backup, inventing HTML when a file exists.
# Desk / account / connect
Load only when the user explicitly asks to sign in, mint or revoke keys, manage
the account, or connect MCP from the desk. Do **not** invent Stripe customer
IDs, key plaintext, plan prices, or checkout steps.
## Desk URLs
| Need | Link |
| --- | --- |
| Account / mint publisher key | https://artifactpublisher.com/account/ |
| MCP docs | https://artifactpublisher.com/docs/mcp/ |
| Quickstart | https://artifactpublisher.com/docs/ |
| Agent Skill | https://artifactpublisher.com/docs/skill/ |
| Pricing (user opens themselves) | https://artifactpublisher.com/pricing/ |
| Privacy | https://artifactpublisher.com/privacy/ |
| Imprint / operator | https://artifactpublisher.com/imprint/ |
| Support | contact@artifactpublisher.com |
A desk `#mcp` deep-link may land later; until then, point people at **Account**
plus MCP docs. Do not invent fragment URLs.
## Keys
1. User mints a scoped publisher key in the desk UI.
2. Key is **shown once**; server stores only a hash.
3. Agent / skill: put the value in env `ARTIFACT_PUBLISHER_KEY` or the client
secret store. **Never** ask the user to paste the key (or any
`ar_pk_…` / `ar_oat_…` / refresh token) into chat.
4. If a key was exposed in chat, logs, or a repo: tell the user to revoke it in
the desk and mint a new one — do not “fix” by echoing the old value.
## OAuth connect
When the MCP client supports browser consent:
1. Register resource `https://app.artifactpublisher.com/mcp`.
2. User completes consent in the browser on the site origin.
3. Tokens stay in the **client** secret store.
4. Never ask the user to paste access tokens, refresh tokens, or auth codes
into chat.
Headless / always-on agents (Hermes gateway, OpenClaw operators): publisher key
via env remains the practical path.
## What this skill must not do
- Invent billing portal URLs, Stripe Dashboard links, or invoice amounts.
- Print or store secrets in artifacts, commits, or skill files.
- Claim a CLI name (`artifactpublisher` or otherwise) — none is reserved yet.
- Claim a public `npx skills add` install path until an official registry publish is live.
# Failures
Load after an auth, size, quota, or consent failure. Do not invent success.
## Authentication
| Symptom | What to do |
| --- | --- |
| `401` / missing or bad Bearer | Confirm MCP config uses env `ARTIFACT_PUBLISHER_KEY` or OAuth client store. Point user to https://artifactpublisher.com/account/ to mint/rotate. Never ask them to paste the key or `ar_oat_…` into chat. |
| Keyless call to a write/read tool | Only `initialize`, `tools/list`, and `ping` are keyless. Publish and other tools need a credential. |
| OAuth consent abandoned / expired | Ask the user to complete browser consent again in their MCP client. Do not collect tokens in chat. |
| Wrong workspace / `not_found` on `artifact_id` | Id, slug, or viewer URL must belong to this key’s workspace. Re-check with `list_artifacts`. |
Never fall back to printing Authorization headers, cookies, or raw secrets “to debug.”
## Size and HTML validation
| Symptom | What to do |
| --- | --- |
| Size / UTF-8 limit error | Shrink HTML; inline only what is needed. Live error text is authoritative for the workspace ceiling. |
| `invalid_input` on theme / HTML | Fix per error message (e.g. `ap-theme` marker). Call `get_authoring_guide` rather than inventing CSS. |
| Sandbox “broken” assets | External fonts/images/APIs will not load — inline or drop them. |
## Quota
| Symptom | What to do |
| --- | --- |
| `quota_exceeded` on active artifacts | Revoke or let expire unused artifacts (`revoke_artifact`), or ask the user to manage plan at the desk/pricing page. Do not invent upgrade checkout flows. |
| `quota_exceeded` on versions | Prefer fewer updates; revoke old artifacts if appropriate. Free plan version caps apply — see error details. |
| Rate limit / `429` | Wait for `Retry-After` if present; retry once. Do not hammer the endpoint. |
## Update conflicts
| Symptom | What to do |
| --- | --- |
| `expected_version` mismatch | Another publish won the race. Re-read current version (`list_artifacts` / prior result), explain, and ask before retrying with the user’s HTML. |
## Maintenance / unavailable
If the server returns maintenance or read-only errors: report plainly; prefer
read tools (`get_authoring_guide`, `list_artifacts`, `get_feedback`) when those
still work. Do not switch to a different product or invent a local host.
## Safety
Stop on uncertainty. Do not download or run binaries, curl wrappers, or
“helper scripts” to work around MCP failures.