---
name: publish-site
description: "Move an already-extracted static-site tree into the per-account static-publish surface and emit one canonical path slug. Use when asked to publish, host, or put a site online."
---

# Publish Site

Call `mcp__plugin_admin_admin__publish-site` to move an already-extracted static-site tree into the per-account static-publish surface (`<accountDir>/sites/<slug>/`) and emit one canonical path slug. Pair the slug with `mcp__plugin_admin_admin__public-hostname` to surface the full URL in the same turn.

**Invoked from `specialists:content-producer`** when the brief carries a host-website / publish-site / put-online intent. The slug validation, symlink scan, refusal taxonomy, `mv`, canonical-path selection, and llms.txt refresh all run inside the typed tool — this skill is the intent router, not the implementer.

## When to use

Activate when **both** are true:

- The current turn carries a "host this website" / "publish this site" / "put this online" / equivalent intent.
- A directory tree of HTML + assets is already on disk under `<accountDir>/extracted/<attachmentId>/` (typical output of [unzip-attachment](../unzip-attachment/SKILL.md)), or the conversation already names a source directory under `<accountDir>/`.

Do **not** activate for `.pdf`, `.docx`, slide decks, single-image attachments, or zips whose extracted output is not a directory tree of HTML + assets — those have their own skills (`a4-print-documents`, `deck-pages`, etc.).

## Call

```
mcp__plugin_admin_admin__publish-site
  source:           <absolute path to the extracted source directory>
  slug:             <operator-supplied or operator-confirmed path under sites/>
  siteName?:        <optional llms.txt header; defaults to the last slug segment>
  siteDescription?: <optional one-line blockquote under the llms.txt header>
```

Confirm the slug with the operator before calling if it isn't already explicit in the conversation.

## Surface the result

- **On success** the tool returns `pathSlug` (e.g. `/sites/demo/` or `/sites/demo/brochure.html`). Call `mcp__plugin_admin_admin__public-hostname` next and surface `https://<hostname><pathSlug>` to the operator. The `aeo:` line on the response tells you whether `llms.txt` refresh succeeded; if it failed, the publish still succeeded — relay the URL anyway.
- **On refusal** the tool returns a `refused: <kind>` body with a fixed `Operator action:` guidance line. Relay the guidance verbatim. The five refusal kinds are `unsafe-slug`, `destination-occupied`, `symlink-in-source`, `zero-html`, and `ambiguous-html`. No retry, no improvisation, no fallback server.

## Out of scope

- Extraction. `unzip-attachment` already owns the extract step; the source path is its output.
- DNS, tunnels, certificates, or any public-host configuration. The route at `/sites/*` is the wire contract.
- Cleanup of pre-existing synthetic files left by earlier sessions. A non-empty destination produces `destination-occupied` and the operator cleans up explicitly.
