Publish from any surface you already use.
Browser. Slack. Claude. A Finder drop target on macOS. Your terminal. One backend, one sign-in. The service handles slugging, commits to wwtdigital/artifacts, and deploy polling.
§ 01 Quick start
Five surfaces, one backend. Pick the one that fits your workflow.
/publish§ 02 Web upload
You're already here. Click Publish, sign in with Slack, pick an .html or .md file, submit. The result panel shows the live URL with a copy button.
Optional: set a custom slug. By default the filename (minus extension) is used.
§ 03 Slack /publish
In any channel or DM in the WWT workspace:
/publish
A modal opens with a file picker and an optional slug. Submit and the bot DMs you the live URL when the deploy finishes — usually under a minute.
No separate sign-in step: your Slack handle is verified by the request signature on every /publish call, so the first use is identical to every subsequent one.
Subcommands
/publish list— list your published artifacts./publish delete <slug>— delete one of your artifacts./publish share <slug> <email-or-name>— create a private magic link for one recipient and DM it back to you./publish access <slug>— list who you've shared an artifact with, each with status, view count, and last-viewed date./publish help— usage.
§ 04 Claude (MCP)
Add the publisher as a remote MCP server. Then in any conversation, ask Claude to publish this as an artifact.
Claude Code
claude mcp add wwtd-artifacts --url https://publish.creative-technology.digital/api/mcp
Claude Desktop
Settings → Integrations → Add custom integration:
https://publish.creative-technology.digital/api/mcp
claude.ai web
Settings → Integrations → Add integration, same URL as above.
First tool call from a new client triggers a PKCE OAuth flow through Slack. Approve once, then publish_artifact is callable from any conversation in that client.
§ 05 macOS app
A small native window that mirrors the Slack /publish modal: file picker, optional slug, Publish button, result panel with the live URL. Click the app icon to open the window, or drag a file onto the icon to open it pre-filled.
curl -fsSL https://publish.creative-technology.digital/install.sh | bash
Idempotent — re-run any time to self-update. Clones wwtdigital/vercel-droplet (private, requires GitHub org access), compiles the Swift app, assembles the .app bundle on your Desktop, and runs the first-time Slack OAuth.
What you get
- Artifact Publisher.app on your Desktop. Click to open the publish window.
- Drag an
.htmlor.mdfile onto the app icon — the window opens with that file pre-selected. - Live URL appears in-window when the deploy finishes (~30s), with Open and Copy buttons.
Prerequisites
- macOS 13 or newer (the app uses SwiftUI's modern App lifecycle).
- Xcode Command Line Tools (for
swiftc):xcode-select --install. - Git, with GitHub auth set up for the
wwtdigitalorg. Ifgit clonefails, rungh auth loginfirst. - Optional:
pip3 install Pillowfor the custom icon (installer skips the icon if missing).
Uninstall
rm -rf "$HOME/Desktop/Artifact Publisher.app" \
"$HOME/.local/share/artifact-publisher" \
"$HOME/.local/share/artifact-publisher-repo"
§ 06 CLI
Publish from a terminal on macOS, Linux, or Windows. A single file with zero dependencies — Node stdlib only, nothing to audit, nothing to keep patched. If you're on Windows or Linux, this is your native path; the macOS app installer above is Darwin-only.
curl -fsSL https://publish.creative-technology.digital/cli.sh | sh
Installs wwtd-publish to ~/.local/bin. Re-run any time to update.
irm https://publish.creative-technology.digital/cli.ps1 | iex
Installs to %LOCALAPPDATA%\wwtd-publish and adds it to your user PATH. Open a new terminal afterward.
Usage
wwtd-publish login # one-time Slack sign-in
wwtd-publish deck.html # publish → prints URL + generated password
wwtd-publish list # your artifacts
wwtd-publish whoami / logout
Options
--slug <name>— publish under a specific slug instead of the filename.--password <pw>— set the gate password yourself (minimum 8 characters).--public— publish with no password. A publish-time-only decision; it can't be undone later.--expires <dur>— expire the link:30m,12h,7d,2w.--share <email>— create a revocable per-recipient link. Repeatable.--json— emit the raw API response, for scripting.
Prerequisites
- Node 20 or newer (
node -v). Install from nodejs.org, orbrew install node/winget install OpenJS.NodeJS.LTS. - No GitHub account needed — unlike the macOS app, nothing is cloned.
Uninstall
rm -f "$HOME/.local/bin/wwtd-publish"
rm -rf "$HOME/Library/Application Support/wwtd-publish" # macOS
rm -rf "$HOME/.config/wwtd-publish" # Linux
§ 07 Access control
Every publish is password-protected by default — keep the suggested password, set your own, or explicitly opt out to publish publicly. All gating is enforced server-side, so the raw files in the private repo are never reachable around the gate.
Password
The default. Every surface starts with a generated password (web upload pre-fills one, the Slack modal pre-fills one, and the MCP publish_artifact tool / POST /api/publish auto-generate one and return it in the result — copy it then, it can't be retrieved later). Set your own instead if you prefer; passwords must be at least 8 characters — enforced on every surface (and as a backstop in the hashing layer, so an under-strength gate can never be stored). Visitors are prompted once; a correct password sets a signed cookie scoped to that artifact, and the gate is rate-limited (10 attempts / 15 min per artifact) with a timing-safe scrypt check. Share the password out-of-band. You can change it later from the Manage tab or the MCP update_gate tool, but you can't remove it — going public is a publish-time decision.
Public
The explicit opt-out: uncheck the password option on web, clear the pre-filled field in the Slack modal, or pass public: true on the MCP tool (an empty password on POST /api/publish). No password, no record — anyone with the URL can view it.
Expiry
Give a link a shelf life — after it lapses, every visitor sees an "expired" page, WWT teammates included, and a daily cleanup job takes the artifact offline permanently. Set it as a number of days (expires_in_days on the MCP tools, or the expiry dropdown on web). Treat expiry as final: republish if you need the content back online (the underlying file is archived out of reach and recoverable only by a developer).
Per-recipient sharing
For client-facing work, share with named recipients instead of one shared password. Each recipient gets a unique magic link you can revoke independently, and you can see whether — and when — they've opened it.
- Web: open Publish → Manage, click Share on an artifact, add a recipient (email or name) and an optional expiry, then copy the generated link. If the recipient is an email, you can optionally have the link emailed to them — when email delivery is configured (Resend); otherwise just copy the link and send it yourself (the link is always generated regardless). The panel lists every recipient with status, view count, last-viewed time, and a Revoke button — and once a link has been opened, a History toggle expands its recent view timeline as relative times. (For privacy we record timestamps only, never IP addresses.)
- Slack
/publish:/publish share <slug> <email-or-name>mints a recipient link and DMs it back;/publish access <slug>lists every recipient with status, view count, and last-viewed date. - Claude (MCP): ask Claude to share, list shares, or revoke — backed by the
share_artifact,list_shares, andrevoke_sharetools.
share_artifact(slug: "q3-deck", recipient: "client@acme.com", expires_in_days: 30)
→ { magic_link: "https://artifacts.creative-technology.digital/access/<token>", … }
list_shares(slug: "q3-deck")
→ client@acme.com · viewed 4× · last seen 2 days ago
revoke_share(slug: "q3-deck", grant_id: "<id>") → access ends on the next request
§ 08 Identity
Every surface ends up with the same identity shape — { username } — but the path to get there depends on whether Slack itself can verify you per-request.
- Slack
/publish: your Slack handle comes from the signed slash-command payload. No OAuth, no KV record, nothing to link. - Web, Claude (MCP), and the macOS app: one-time Slack OAuth on first use. The resolved username is cached in KV keyed by
<surface>:<your-id>for 30 days.
When you publish from any surface, your Slack username is recorded as the Published-by: trailer on each commit to wwtdigital/artifacts, and your slugified handle becomes the URL path segment.
To re-link or sign out: open / and click Sign out, or delete ~/.local/share/artifact-publisher/auth.json on the macOS app to force a fresh login.