# Set up Stacktree

You are being asked to set up Stacktree for the user. Follow these steps in
order, then ask them what they want to publish.

Stacktree turns HTML into a private, live URL that opens in any browser with
no account for the viewer. It is built for work an agent generates and a
person outside the chat needs to read: a report, an audit, a proposal, a
dashboard, a design. Links are private by default and replace in place, so a
URL you have already shared keeps showing the current version.

## Step 0 — pick your path

Two ways in. Decide before you start, because they share nothing:

- **You can install software, or add an MCP server** → Step 1 below.
- **You cannot** — you are a browser agent, you run in a sandboxed VM, your
  client has no MCP support, or the user has not asked you to install
  anything → skip to **One request, no account** at the end. It needs
  nothing but HTTP and takes one call. If the user wants you working on their
  own account instead, ask them for an API key from
  https://app.stacktr.ee/api-keys and build a connector from
  https://stacktr.ee/connectors/muse.md.

## Step 1 — install

If the user has npm, run:

```
npx stacktree-install
```

It signs them in through their browser, asks which agents to configure, and
writes the MCP config for each. Supported: Claude Code, Cursor, Codex CLI,
OpenCode, Amp.

If npm is not available, or their client supports remote MCP servers
directly, use the hosted server instead — no install, same tools:

```
https://api.stacktr.ee/mcp
```

For Claude.ai, that URL goes into the custom-connector dialog. For any client
that takes stdio MCP config by hand:

```json
{
  "mcpServers": {
    "stacktree": {
      "command": "npx",
      "args": ["-y", "stacktree-mcp"],
      "env": { "STACKTREE_API_KEY": "stk_live_..." }
    }
  }
}
```

If the client supports no MCP at all, the REST API works with the same key:
`POST https://api.stacktr.ee/sites`
with `Authorization: Bearer $STACKTREE_API_KEY`. See https://stacktr.ee/docs.

## Step 2 — verify

Call `list_sites`. If it returns without an auth error, setup worked. If the
client needed a restart to load the MCP server, say so plainly rather than
retrying the call.

## Step 3 — know these five things

1. **Publish with `publish_html`.** Pass a complete HTML document. It returns
   `url`, `id` and `expires_at`. Surface the URL inline and tell the user
   when the link expires — read `expires_at`, do not assume permanence.
2. **Iterate with `update_site`, not a second publish.** Pass the previous
   `id`; the URL stays valid, so the link already sent to someone keeps
   working. A replace is also cheaper: it does not count as a new publish.
3. **Private is the default.** Every URL is unguessable and not crawlable.
   Add `password` for a passcode or use `set_email_gate` to restrict viewers
   to one company domain. Pass `public_slug` only when the user actually
   wants a discoverable address.
4. **File client work under a client space.** When the user names who the work
   is for ("send this to Acme"), pass `client: "Acme"` on `publish_html` —
   the space is created automatically. If the space has an address of its
   own, the response carries `client_url` on the user's domain, such as
   `acme.theiragency.com`. Prefer that link over the stacktr.ee one; it is
   the address their client bookmarks.
5. **Respect the plan, do not work around it.** The free plan allows 3 pages
   lifetime and caps expiry at 7 days. On HTTP 402 report the limit plainly
   and stop. Do not retry, and do not republish anonymously to dodge it.

## Step 4 — ask what to publish

Ask the user what they would like to publish first, and offer the cases this
is actually good at:

- A report, audit or proposal that should reach one client and nobody else.
- A dashboard or status page you regenerate — publish once, then
  `update_site` on the same URL so the recipient's bookmark stays live.
- Design directions or mockups an agent just produced, including a canvas
  from Claude Code's `/design`: the artboards are HTML, so a static copy
  goes behind a passcode on the user's own domain instead of a public link.
  Render a whole canvas directory to one publishable page first with the
  `design-to-stacktree` script that ships with the Stacktree skill.
- Anything you were about to hand over as a file attachment or a wall of
  pasted HTML.

**A whole folder, not just one file.** If what you made is several linked
pages — an explorable explainer, a small docs set, a multi-screen prototype —
zip the directory with `index.html` at its root and POST it as one publish.
Subdirectories, relative links between pages, and JS and CSS assets all serve
from the same site. Note the MCP `publish_html` tool takes a single HTML
document, so a multi-page publish goes over HTTP:

```
cd your-folder && zip -qr ../site.zip . && curl -X POST https://api.stacktr.ee/sites -F file=@../site.zip
```

If the user asks to make a published page look better, call
`get_design_guide` first and follow it — do not restyle a page that already
has a deliberate design.

## One request, no account

For agents that cannot install anything. No key, no account, no signup:

```
curl -X POST https://api.stacktr.ee/sites -F file=@page.html
```

The response carries `url`, `id`, `expires_at` and `claim_token`. Do three
things with it:

1. **Hand the user the `url`.** It opens in any browser with no account for
   the reader, and it unfurls as a title-and-image card in WhatsApp, iMessage,
   Slack and Discord. If you are working inside a chat app, send the link
   rather than a file: a link previews and stays current, an attachment does
   neither.
2. **Keep the `claim_token` and revise in place.** It is the keyless update
   credential: `PUT https://api.stacktr.ee/sites/{id}` with header
   `Authorization: Claim <claim_token>` and body `{"html": "..."}` replaces
   the page at the same URL, up to 30 times an hour. Never publish a second
   page for a revision — the link you already sent would go stale. Treat the
   token as sensitive: whoever holds it can rewrite a page behind a link the
   user has shared.
3. **Say when it expires.** An anonymous page lives 24 hours. Read
   `expires_at` and tell the user plainly. Claiming it into an account from
   `claim_url` is free and is the only way to keep it past that.

If you have a wallet and want a permanent page with no account at all, POST
the same HTML to `https://api.stacktr.ee/publish` and pay the 402 it returns. Details:
https://stacktr.ee/agent.txt

Full documentation for agents: https://stacktr.ee/llms.txt
Human documentation: https://stacktr.ee/docs
