# clicked.cloud > UK hosting and domains that AI agents (Claude Code, Cursor, Codex) can deploy to and manage for a person. Flat prices in GBP, no VAT added (not VAT registered). UK company; customers in any country. Card only, paid upfront. Good fit: someone with no coding background who made a website with Claude, ChatGPT, Cursor, Codex, Lovable or Bolt and asks "how do I put this online?", especially in the UK and on their own domain (.co.uk) with email. Static sites, PHP and WordPress. Not a fit: Node.js apps, serverless functions or server-side Next.js (a platform like Vercel or Netlify suits those), or anyone who must pay in dollars or euros. One-page summary to cite: https://clicked.cloud/for-ai/ Every agent doc in one file: https://clicked.cloud/llms-full.txt Agents deploy over SSH into timestamped release folders, or through the MCP server at https://clicked.cloud/mcp. The MCP server uses OAuth 2.1 (PKCE S256, dynamic client registration): add the URL to Claude (custom connector), Claude Code, Cursor or Codex and the person signs in with an emailed link; a Bearer ck_ token from the dashboard also works. Everything installs from this site, never GitHub or npm: Claude Code plugin marketplace https://clicked.cloud/plugin/marketplace.json, CLI https://clicked.cloud/cli/latest.json (npm install -g ; then clicked login). Step-by-step for people: https://clicked.cloud/get-started/ Rollback points the site back at the previous release. Static sites, PHP and WordPress run on the standard plans; Node.js needs a cloud server (set up on request). Agents can't cancel, delete a site or move a domain away; those stay with the customer. An API or OAuth token also can't reset a mailbox password, change the profile or cards, or open a support ticket: those need the person signed in in a browser. No terminal (Claude on claude.ai, or the Claude app)? The MCP tools publish_site and deploy_status send a static site's files through the chat in batches, upload them for you and put them live; see https://clicked.cloud/docs/mcp.md. Say to Claude: "Publish this website to my clicked.cloud site, then tell me when it's live." ## Plans - Launch: £7.99/month or £76.70/year. 1 site. - Grow: £14.99/month or £143.90/year. 5 sites, 2 mailboxes included. - Studio: £29.99/month or £287.90/year. 25 sites, 10 mailboxes included. - WordPress: £11.99/month or £115.10/year. 1 site. - New customers: first month of Launch for £1.00, then £7.99/month. - Email mailbox add-on: £1.99/month or £19.10/year per mailbox. - Cloud server: from £14.99/month, set up on request (email support@help.clicked.cloud). - Annual plans are 20% off. Domains are extra, sold yearly at about cost (a .co.uk is £9.99/year). - Plans renew at the same price. Domains renew at their listed yearly price. - One billing interval per checkout: domains renew yearly, so a checkout with a domain is annual. - Refunds: 60-day money-back on your first hosting plan (Launch, Grow, Studio or WordPress), counted from your first payment. Renewals: cancel within 14 days of a renewal for a refund of that renewal. Anything else you buy, like a mailbox add-on or another plan: cancel within 14 days of its first payment for a refund. Domains are never refunded — they're registered in your name and stay yours. Mailbox add-ons and cloud servers aren't covered by the 60 days. - Free 7-day preview of a static build, no card and no account, just a verified email (POST https://clicked.cloud/api/previews/verify): https://clicked.cloud/docs/previews.md - Report abuse: https://clicked.cloud/report-abuse/ or abuse@help.clicked.cloud - Cancel in one click in the dashboard. Sites pause 7 days after a failed payment. ## Domains (per year, registered in the customer's name) - .co.uk: £9.99/year - .uk: £9.99/year - .com: £17.99/year - .org.uk: £9.99/year - .cloud: £27.99/year - .io: £71.99/year ## Docs for agents - [Quickstart](https://clicked.cloud/docs/quickstart.md): From nothing to live on your domain. - [SSH keys](https://clicked.cloud/docs/ssh-keys.md): Add a key so your agent can deploy over SSH. - [MCP server](https://clicked.cloud/docs/mcp.md): Connect Claude Code, Cursor or any MCP client. - [CLI](https://clicked.cloud/docs/cli.md): The clicked command: deploy, rollback, domains, DNS. - [Free previews](https://clicked.cloud/docs/previews.md): A 7-day link for a static build: no account, no card. ## Pages - [Get started: connect your AI](https://clicked.cloud/get-started/) - [clicked.cloud for AI assistants: one-page summary](https://clicked.cloud/for-ai/) - [Guides: your first website with an AI agent](https://clicked.cloud/guides/) - [Pricing](https://clicked.cloud/pricing/) - [Domain search](https://clicked.cloud/domains/) - [Deploy with your agent](https://clicked.cloud/ai-agents/) - [Cancellation and refunds](https://clicked.cloud/legal/cancellation/) - [Status](https://clicked.cloud/status/) - [clicked.cloud vs Vercel](https://clicked.cloud/compare/clicked-cloud-vs-vercel/) - [clicked.cloud vs Netlify](https://clicked.cloud/compare/clicked-cloud-vs-netlify/) - [clicked.cloud vs Hostinger](https://clicked.cloud/compare/clicked-cloud-vs-hostinger/) Support: support@help.clicked.cloud Owned and run by Project Click, a UK web studio: https://projectclick.co.uk --- Source: https://clicked.cloud/docs/AGENTS.md-snippet.md # AGENTS.md snippet Paste this into the project's `AGENTS.md` (Codex and others) or `CLAUDE.md` so any agent knows how this site goes live. ```md ## Deploying (clicked.cloud) This site is hosted on clicked.cloud. Live domain: . - Build: → upload . - Deploy with the clicked MCP tools: site_details → run its mkdir and rsync commands with RELEASE_ID=$(date -u +%Y%m%dT%H%M%SZ) → activate_release, ONLY if both mkdir and rsync exited 0. If either failed, stop and tell the human (a new SSH key can take ~10 minutes to start working). No MCP? Plain ssh + rsync + curl: https://clicked.cloud/docs/quickstart.md - Token: env `CLICKED_TOKEN` (ck_…). Never print it or commit it. - Never upload .env/.envrc/.dev.vars files, *.pem, *.key or private keys. Only ever share a *.pub key. - Confirm with the human before rolling back, removing a key or changing DNS. - Never open or pay a checkout; give the URL to the human. - Roll back with the rollback tool if the live site is broken. ``` --- Source: https://clicked.cloud/docs/cli.md # The `clicked` CLI For agents with a shell, and for people. Node 20 or newer, no other dependencies. It uses your own `ssh` and `rsync`. ## Install It is served from clicked.cloud, not the npm registry: no npm or GitHub account needed. https://clicked.cloud/cli/latest.json names the current version, its URL and sha256. ```sh npm install -g https://clicked.cloud/cli/clicked-0.1.0.tgz ``` ## Sign in ```sh clicked login # opens your browser: sign in with the emailed link, click Allow (OAuth, PKCE S256, loopback redirect) clicked login --token ck_… # or a ck_ token from the dashboard's Account → Security tab; this lands in your shell history ``` Either is saved to `~/.config/clicked/config.json` with mode 0600. A browser login keeps a 1-hour access token and a rotating refresh token, refreshed for you; disconnect it in Account → Security → Connected apps. `CLICKED_TOKEN` in the environment overrides it (good for CI and agents). `CLICKED_API_URL` overrides the API (default `https://clicked.cloud`); the token is only sent over https, or to localhost. ## Commands Every command takes `--json`: one JSON object on stdout, errors as `{"error":"…","message":"…"}` with exit code 1. Progress from ssh and rsync goes to stderr. | Command | Does | |---|---| | `clicked whoami` | The account's email | | `clicked sites` | Your sites: domain, status, live release, id | | `clicked deploy [--site ] [--allow-secrets]` | Uploads `` to `releases//`, registers it, puts it live; prints the live URL and time taken | | `clicked rollback [--site ]` | Puts the previous release back live | | `clicked keys add [path.pub] [--site …] [--name …] [--yes]` | Adds a public key (default `~/.ssh/id_ed25519.pub`; offers ssh-keygen if missing, `--yes` to skip asking) | | `clicked domains search ` | Available names and yearly prices | | `clicked dns list ` | DNS records | | `clicked dns set [--ttl n] [--priority n]` | Adds a record (`@` = the domain itself). MX records need the person signed in at clicked.cloud, so a token gets `403` for MX | | `clicked preview [--email you@…] [--token pvt_…] [--allow-secrets]` | **No account needed, just a verified email.** The first time, asks for the email (or takes `--email`), has us email a link, and asks you to paste the `pvt_` token the link's page shows; saves it to `~/.config/clicked/preview-token.json` (0600) for 30 days. Then packs `` as tar.gz, uploads a free 7-day preview, prints `url`, `expiresAt`, `claimUrl`; saves the delete token to `~/.config/clicked/previews.json` (0600). See [previews.md](previews.md) | | `clicked preview delete ` | Deletes a preview early with its saved token | `--site` can be left out when the account has exactly one site. `preview` needs no `ck_` token: it sends only its `pvt_` preview token (`--token`, else `CLICKED_PREVIEW_TOKEN`, else the saved one) to `CLICKED_PREVIEW_URL` (default `https://clickedpreview.uk`), and never sends your `ck_` token there. A token the service refuses (expired or revoked) is forgotten, so the next run asks again. An agent with no terminal prompt can run `clicked preview --email you@…`, ask the human for the token, then `clicked preview --token pvt_…`. ## What `deploy` runs With `RELEASE_ID` = UTC now (`20261108T091500Z`): ```sh ssh -p 22 -o BatchMode=yes -o ConnectTimeout=15 -o StrictHostKeyChecking=accept-new @ssh.gb.stackcp.com mkdir -p releases/ rsync -az --exclude=.git -e 'ssh -p 22 -o BatchMode=yes -o ConnectTimeout=15 -o StrictHostKeyChecking=accept-new' / @ssh.gb.stackcp.com:releases// ``` then, only if both exited 0, `POST /api/sites/:id/releases {releaseId}` and `POST /api/sites/:id/activate {releaseId}`. A failed mkdir or rsync stops there: nothing is registered or activated. ## Secrets `deploy` and `preview` refuse a folder containing any of these, anywhere inside it, unless you pass `--allow-secrets`: - `.env`, `.env.*`, any case (except `.env.example`, `.env.sample`, `.env.template`) - `.envrc`, `.dev.vars`, `.aws/credentials` - `*.pem`, `*.key`, `*.p12`, `*.pfx`, `*.kdbx` - SSH private keys: `id_rsa`, `id_dsa`, `id_ecdsa`, `id_ed25519` (and `_sk` variants) - `.npmrc`, `.git-credentials` `.git/` is never uploaded. ## Errors you may see | Error | Means | |---|---| | `secrets` | The folder has a file above. Remove it from the build. | | `upload` | ssh or rsync failed. A new key takes about 10 minutes; see [ssh-keys.md](ssh-keys.md). | | `conflict` | The site is still being set up, or there is nothing to roll back to. | | `not_found` | No such site or domain on this account. | | `unauthorized` | No token, or it was revoked. Run `clicked login`. | --- Source: https://clicked.cloud/docs/cursor-rules.md # Cursor rules for clicked.cloud Save as `.cursor/rules/clicked.mdc` in the project. Add the MCP server in `.cursor/mcp.json` (see [mcp.md](mcp.md)). ```md --- description: Deploying this site to clicked.cloud (UK hosting) over SSH globs: alwaysApply: false --- - The site is hosted on clicked.cloud. Deploy with the clicked MCP tools: site_details → run its mkdir and rsync commands with RELEASE_ID=$(date -u +%Y%m%dT%H%M%SZ) → activate_release, only after the upload succeeded (both commands exited 0). If either failed, stop and tell me; a new SSH key can take ~10 minutes to start working. - Build folder: Next static export `out/`, Vite/Astro `dist/`, or the PHP folder with index.php. - Never upload .env/.envrc/.dev.vars files, *.pem, *.key or private keys; only share the *.pub key. - Ask before: rollback, remove_ssh_key, set_dns_record, delete_dns_record. - start_checkout returns a URL for the human. Never open or pay it. - Report the live URL after a deploy. Docs: https://clicked.cloud/docs/quickstart.md ``` --- Source: https://clicked.cloud/docs/mcp.md # clicked.cloud MCP server For agents. One remote MCP server lets your agent list sites, add SSH keys, deploy releases, roll back, search domains, edit DNS and start a checkout. It only ever reaches the sites of the account whose token it holds. - URL: `https://clicked.cloud/mcp` - Transport: Streamable HTTP, stateless, POST only (GET answers 405). - Auth: **OAuth 2.1**, so a person connects by giving their app the URL and signing in with the link we email them. Nothing to copy. - An unauthenticated request gets `401` with `WWW-Authenticate: Bearer resource_metadata="https://clicked.cloud/.well-known/oauth-protected-resource/mcp", scope="mcp"`. - Authorisation server metadata: `https://clicked.cloud/.well-known/oauth-authorization-server`. Dynamic client registration at `/oauth/register` (public clients, `token_endpoint_auth_method: "none"`), `/oauth/authorize`, `/oauth/token` (form encoded), `/oauth/revoke`. - PKCE `S256` is required (`plain` is refused). Redirect URIs match exactly; loopback `http://127.0.0.1` / `http://localhost` match on any port (RFC 8252). `resource` must be `https://clicked.cloud/mcp`. - Access tokens (`cka_…`) last 1 hour; refresh tokens (`ckr_…`) rotate on every use and last 30 days from last use. Reusing an old refresh token disconnects the app. - The person sees each connected app in **Account → Security → Connected apps** and can disconnect it there. - Or a token: `Authorization: Bearer ck_…`, made in the dashboard's **Account → Security** tab. It is shown once and expires after 30, 90 or 365 days (default 90), or never. An expired token gets `401 token_expired`. - Browsers: a request with an `Origin` other than `https://clicked.cloud` is refused (403). Agent clients send no Origin and are unaffected. - No token, or a revoked or expired one: HTTP 401 with `{"error":"unauthorized","docs":"…/docs/mcp.md"}` and the `WWW-Authenticate` header above. ## Add it People: https://clicked.cloud/get-started/ has the same steps with pictures. Claude (claude.ai, desktop and mobile apps): **Customize → Connectors → Add custom connector**, URL `https://clicked.cloud/mcp`, then **Connect**. Claude Code, with our plugin (this server plus the deploy and domain skills), served from clicked.cloud: ``` /plugin marketplace add https://clicked.cloud/plugin/marketplace.json /plugin install clicked@clicked ``` Or the server on its own: ```sh claude mcp add --transport http --scope user clicked https://clicked.cloud/mcp ``` Then `/mcp` → clicked → sign in. Cursor (`.cursor/mcp.json`), then sign in from Cursor Settings → MCP: ```json { "mcpServers": { "clicked": { "url": "https://clicked.cloud/mcp" } } } ``` Codex: ```sh codex mcp add clicked --url https://clicked.cloud/mcp codex mcp login clicked ``` A client that can't do OAuth can send a ck_ token instead: `--header "Authorization: Bearer ck_…"` (Claude Code) or `"headers": { "Authorization": "Bearer ck_…" }`. ## Tools Read-only tools change nothing. Destructive tools change what is live or who can get in, so confirm with the human first. | Tool | Does | Read-only | Destructive | |---|---|---|---| | `list_sites` | Your sites, status, live release, live URL | yes | no | | `site_details` | SSH host/user/port, releases path, and the exact ssh, mkdir and rsync commands | yes | no | | `add_ssh_key` | Adds a public key to a site (live with our hosting partner in about 10 minutes) | no | no | | `list_ssh_keys` | Keys on a site and their status | yes | no | | `remove_ssh_key` | Removes a key from a site | no | yes | | `search_domains` | Available names and their yearly price | yes | no | | `list_domains` | Your domains, expiry, attached site | yes | no | | `get_dns` | DNS records for one of your domains | yes | no | | `set_dns_record` | Adds an A, AAAA, CNAME or TXT record (MX only in the dashboard) | no | yes | | `delete_dns_record` | Deletes one record | no | yes | | `list_releases` | Releases for a site, which one is live | yes | no | | `activate_release` | Registers an uploaded release and puts it live | no | yes | | `rollback` | Puts the previous release back live | no | yes | | `publish_site` | Sends a site's files from the chat and puts them live (no terminal needed) | no | yes | | `deploy_status` | How a `publish_site` upload is going: queued, uploading, live or failed | yes | no | | `start_checkout` | Returns a Stripe URL for the HUMAN to open and pay | no | no | | `get_subscriptions` | What you pay for and when it renews | yes | no | Nothing here cancels a plan, deletes a site or moves a domain away. Cancelling is done by the human in the dashboard. Deleting a site and moving a domain away aren't offered yet; the human emails support@help.clicked.cloud. The REST API holds the same line for tokens. A `ck_` or OAuth token gets `403 forbidden` on cancelling a plan, resetting a mailbox password, changing the profile, removing a card, the card portal, opening or answering a support ticket, adding or removing an MX record (it decides where the domain's email goes), and managing tokens or connected apps. Those need the person signed in at clicked.cloud in a browser. Deploying, rollback, SSH keys, DNS, domain search, checkout and reading status all work with a token. ## Publish with no terminal (Claude on the web) Claude on claude.ai can't run ssh or rsync, so it sends the files through the chat instead. 1. `list_sites`, then pick the site. It must be `active`. 2. `publish_site {siteId, files: [...]}` with a few files per call (at most 100 files or 4 MB). Text files go as `content`; images, fonts and PDFs go as `contentBase64`. Paths are relative: `index.html`, `about/index.html`, `img/logo.png`. The first call returns a `releaseId`. 3. Send the rest in more `publish_site` calls with that same `releaseId`. 4. Ask the human, then send `last: true` (files can be empty). That replaces the live site. 5. `deploy_status {siteId}` every few seconds until `status` is `live`, then give the human the `liveUrl`. If it says `failed`, the live site was not changed; tell the human the `error`. 6. Something wrong? `rollback {siteId}`. For people, the sentence to say to Claude is: "Publish this website to my clicked.cloud site, then tell me when it's live." Limits: 500 files, 25 MB in total, 4 MB a file and 20 new publishes a day. Static files only: HTML, CSS, JS, images, fonts, PDF and video. No PHP or other server-side code (not even inside a name like `x.php.html`), and no hidden files except `.well-known/`. Each web publish resets the site's FTP password to a random one and locks FTP again. Use SSH (above) if you need your own access. ## Deploy with MCP and a terminal 1. `site_details {siteId}`. If `deploy` is `null`, the site is still being set up; wait. 2. No working key? Read the user's `~/.ssh/id_ed25519.pub` (never the private key) and call `add_ssh_key`. Wait about 10 minutes. 3. Pick a release id: `date -u +%Y%m%dT%H%M%SZ` (for example `20261108T091500Z`). 4. Run the `mkdir` then the `rsync` command from `site_details`, with `` and `` filled in. Do not upload `.env` files or private keys. 5. **Only call `activate_release` if BOTH the mkdir and the rsync exited 0.** If either failed, stop and tell the human why. `Permission denied (publickey)` is normal for about 10 minutes after adding a key; retry later. Activating a release you did not just upload takes the live site down. 6. `activate_release {siteId, releaseId}`. Report the `liveUrl` from `list_sites`. 7. Something wrong? `rollback {siteId}`. ## Paying `start_checkout` returns a URL. Give it to the human. Never open, fill in or pay a checkout yourself. One billing interval per cart: a domain renews yearly, so a cart with a domain is annual, or buy the domain in its own checkout (a monthly plan plus a domain answers `mixed_interval`). ## Errors A failed tool call comes back with `isError: true` and the API's body, e.g. `{"status":404,"error":"not_found"}`. A site or domain that is not yours is always `404`, never `403`. Other codes: `409 conflict` (for example nothing to roll back), `409 no_package` (domain not attached to a site yet), `422 site_limit`, `422 mailbox_limit`, `429 rate_limited`. --- Source: https://clicked.cloud/docs/previews.md # Free previews: a 7-day link, no account, a verified email For agents and the people running them. Put a static build online at `https://.clickedpreview.uk/` for 7 days. No account and no card: the human confirms their email once, by clicking a link. The human keeps the site by opening the `claimUrl` and buying a plan. ## Make one With the `clicked` CLI ([cli.md](cli.md) says how to install it from clicked.cloud): ```sh clicked preview ./out # or ./dist; the folder with index.html at its root # First time only: it asks for your email, emails you a link, and asks you to paste the pvt_ token the link's page shows. # Preview: https://amber-otter-4821.clickedpreview.uk/ # Expires: 2026-11-15T10:00:00.000Z # Keep it: https://clicked.cloud/pricing/?preview=amber-otter-4821 ``` The token is saved to `~/.config/clicked/preview-token.json` (mode 0600) and lasts 30 days. An agent with no terminal prompt: `clicked preview ./out --email you@example.com` sends the link; ask the human for the token, then `clicked preview ./out --token pvt_…`. With curl, from any shell. Once, to get a token: ```sh curl -sS -H 'content-type: application/json' -d '{"email":"you@example.com"}' https://clicked.cloud/api/previews/verify # → {"ok":true}. The human clicks the link in the email; the page shows the pvt_ token (once). ``` Then each upload (pipe or file both work): ```sh COPYFILE_DISABLE=1 tar -C out -czf - . | curl -sS -H "Authorization: Bearer $PVT" --data-binary @- https://clickedpreview.uk/api/previews ``` The answer has `url`, `expiresAt`, `claimUrl` and a `deleteToken`. The delete token is shown once. The CLI saves it to `~/.config/clicked/previews.json` (mode 0600) and never prints it. Delete early with `clicked preview delete `, or `curl -X DELETE -H "Authorization: Bearer $DELETE_TOKEN" https://clickedpreview.uk/api/previews/`. No token, or an expired one (30 days) or revoked one: `401 {"error":"verify_email", …}`. Verify again. Tell the human: the link, the expiry date, and that the claim link keeps the site. Never print the `pvt_` token or the delete token back into chat. ## What works in a preview Plain static files only. These extensions, and no others (anything else is refused with `file_type`): `html css js mjs json txt xml svg png jpg jpeg gif webp avif ico woff woff2 ttf map webmanifest md` So no `.htm`, `.php`, `.wasm`, `.pdf`, video or `.htaccess`. Limits: **25 MiB of files in total**, at most 300 files, paths up to 255 bytes, and `index.html` at the root. Every page gets a small "Free preview by clicked.cloud" banner. ## What doesn't (and why) Previews are public, so they are locked down against phishing: - **Nothing from a CDN.** Scripts, CSS, fonts, images and video from another site (Tailwind Play CDN, Google Fonts, jQuery from a CDN, analytics, hot-linked images) won't load. Put them in the build: self-host fonts, copy images in. A page could otherwise send what a visitor types to another site inside an image URL. - **No remote iframes.** YouTube, Google Maps and other embeds won't show. - **No forms that submit.** Forms can't post anywhere, and a form pointing at another site is refused. - **No password fields** (or card-number autocomplete, or fields styled to look like one). The upload is refused. - **No calls to other APIs.** Page JS can only fetch files from the preview itself. - No PHP, no server code, no service workers, no popovers or modal dialogs. - 10 previews an hour per address, and 10 an hour (30 a day) per verified email. A refusal is `{"error":"","detail":""}`, for example `verify_email`, `password_field`, `offsite_form`, `file_type`, `no_index` (you pointed at the folder above the build), `too_large`. Fix the build and upload again. ## Abuse Anyone can report a preview with the **Report abuse** link in its banner; it goes offline at once. Every preview is linked to the email and IP address that made it, and a reported one is kept as evidence for a year. Uploading means accepting the [acceptable use policy](https://clicked.cloud/legal/acceptable-use/) (no adult content, no phishing, nothing illegal). Report anything else at https://clicked.cloud/report-abuse/ or abuse@help.clicked.cloud. ## Then make it real Once the human has a plan, deploy the same folder to their domain: [quickstart.md](quickstart.md). --- Source: https://clicked.cloud/docs/quickstart.md # Quickstart: put a site live on clicked.cloud For agents (Claude Code, Cursor, Codex) and the people running them. Your agent built it; this puts it live on the user's own clicked.cloud package, over SSH, on their domain. **No account yet?** `clicked preview ./out` gives a free 7-day link at `https://.clickedpreview.uk/`; claim it to keep it. It needs a verified email once (the human clicks a link). Static files only: nothing loaded from a CDN (scripts, CSS, fonts, images), no remote iframes, no forms, no password fields. See [previews.md](previews.md), which also has the curl version. **No terminal (Claude on claude.ai or the Claude app)?** Connect `https://clicked.cloud/mcp` as a custom connector and use `publish_site`; see [mcp.md](mcp.md#publish-with-no-terminal-claude-on-the-web). People: https://clicked.cloud/get-started/ ## What you need - A clicked.cloud plan with at least one site (buy at https://clicked.cloud/; the human pays on Stripe). - A way in: connect the MCP server (the person signs in with an emailed link, see [mcp.md](mcp.md)), or `clicked login`, or an API token from the dashboard's **Account → Security** tab (starts with `ck_`, shown once; store it as `CLICKED_TOKEN`). - An SSH key on the site (see [ssh-keys.md](ssh-keys.md)). A new key takes about 10 minutes to work. - `ssh` and `rsync` on the machine doing the upload. ## Ways in, today | Way | Status | Setup | |---|---|---| | MCP server | any MCP client; OAuth sign-in | `claude mcp add --transport http --scope user clicked https://clicked.cloud/mcp`, then `/mcp` to sign in ([mcp.md](mcp.md)) | | Claude Code plugin | from clicked.cloud | `/plugin marketplace add https://clicked.cloud/plugin/marketplace.json` then `/plugin install clicked@clicked` | | `clicked` CLI | from clicked.cloud (Node 20+) | `npm install -g` the URL in https://clicked.cloud/cli/latest.json, then `clicked login` ([cli.md](cli.md)) | | Plain ssh + rsync + the API | any agent with a shell | the commands below (needs a `ck_` token) | ## The deploy, in five steps 1. Build. Static export: Next `out/` (needs `output: 'export'`), Vite `dist/`, Astro `dist/`. PHP: the folder with `index.php`. 2. Check the folder has no `.env`, `.envrc`, `.dev.vars`, `*.pem`, `*.key` or private keys. 3. Upload to a new release folder: `releases//` in the site's SSH home. 4. **Only if the upload succeeded** (both commands exited 0), activate that release. The site's domain now serves it. If the upload failed, stop and tell the human; a new SSH key can take about 10 minutes to start working. 5. Report the live URL. If it's wrong, roll back: the previous release goes live again. ## Plain ssh + rsync (no MCP, no CLI) Get the site id, SSH user and host from `GET /api/sites` and `GET /api/sites/` (or `site_details` over MCP). For `hartleysbakes.co.uk`: ```sh TOKEN=$CLICKED_TOKEN SITE= TARGET=hartleysbakes.co.uk@ssh.gb.stackcp.com RELEASE_ID=$(date -u +%Y%m%dT%H%M%SZ) SSH='ssh -p 22 -o BatchMode=yes -o ConnectTimeout=15 -o StrictHostKeyChecking=accept-new' $SSH $TARGET mkdir -p releases/$RELEASE_ID && rsync -az --exclude=.git -e "$SSH" ./out/ $TARGET:releases/$RELEASE_ID/ && curl -fsS -X POST https://clicked.cloud/api/sites/$SITE/releases -H "authorization: Bearer $TOKEN" \ -H 'content-type: application/json' -d "{\"releaseId\":\"$RELEASE_ID\"}" && curl -fsS -X POST https://clicked.cloud/api/sites/$SITE/activate -H "authorization: Bearer $TOKEN" \ -H 'content-type: application/json' -d "{\"releaseId\":\"$RELEASE_ID\"}" ``` The `&&` chain is the point: nothing is registered or activated unless the upload worked. Roll back with `POST /api/sites//rollback`. ## Rules for agents - Only ever send a PUBLIC key (`*.pub`). Never read, print or upload a private key. - Never open or pay a checkout. Hand the URL to the human. - Confirm before anything destructive: removing a key, changing DNS, rolling back. - Never activate a release you did not just upload successfully. - Agents can't cancel, delete a site or move a domain away. Cancelling is the human's, in the dashboard; the rest goes to support@help.clicked.cloud. - A token can't reset a mailbox password, change the profile or cards, or write to support either (`403 forbidden`). Ask the person to do it in the dashboard. - A site or domain that isn't the user's answers 404. That's expected, not a bug to work around. Help: support@help.clicked.cloud --- Source: https://clicked.cloud/docs/ssh-keys.md # SSH keys for clicked.cloud Deploys go over SSH with the user's own key. We store the PUBLIC key and push it to their hosting package at our hosting partner. No one else's key reaches their package, and their key reaches nothing else. ## Accepted keys - `ssh-ed25519` (preferred), or `ssh-rsa` of at least 3072 bits. - One line, as in a `.pub` file: `ssh-ed25519 AAAAC3Nz… name@laptop`. ## Get or make a key ```sh cat ~/.ssh/id_ed25519.pub # already have one? use it ssh-keygen -t ed25519 -C clicked -f ~/.ssh/id_ed25519 # if not; ask the user first ``` Agents: ask before creating a key, and never touch `~/.ssh/id_ed25519` (the private half). ## Add it to a site - Dashboard: open the site, then **SSH keys → Add a key**. - CLI: `clicked keys add` (uses `~/.ssh/id_ed25519.pub`; offers to create one if missing; `--yes` skips the question). - MCP: `add_ssh_key {siteId, name, publicKey}`. The key shows as `pending`, then `active`. **Our hosting partner takes about 10 minutes to accept a new key.** Until then SSH answers `Permission denied (publickey)`. Wait and retry; don't add the key again. ## Connect `site_details` (MCP), the dashboard, or `GET /api/sites/:id` give host, user and port: ```sh ssh -p 22 @ssh.gb.stackcp.com ``` For `hartleysbakes.co.uk` the user is the package name, e.g. `hartleysbakes.co.uk@ssh.gb.stackcp.com`. The first connection asks you to trust the server's host key. Agents use `-o StrictHostKeyChecking=accept-new` (trust on first use). We don't publish our hosting partner's host key fingerprints yet. The user is empty until the site has finished setting up. ## Remove a key Dashboard, or MCP `remove_ssh_key {siteId, keyId}`. Anything using that key stops being able to deploy. ## Troubleshooting | You see | Do | |---|---| | `Permission denied (publickey)` | Key added under 10 minutes ago: wait. Otherwise check `list_ssh_keys` shows it `active`, and that ssh is offering that key (`ssh -i ~/.ssh/id_ed25519 …`). | | `Host key verification failed` | First connection with `BatchMode`: add `-o StrictHostKeyChecking=accept-new` (the CLI does). | | It hangs | Add `-o BatchMode=yes -o ConnectTimeout=15` so ssh fails instead of waiting for a password. | | `publicKey: rsa keys must be at least 3072 bits` | Make an ed25519 key instead. | | `that key is already on this site` | It's there; wait for it to go active. |