Command line
The Spaicely CLI (open source, MIT) is for people who build their site themselves, with Jekyll, Hugo, Eleventy, Astro or plain HTML, and for AI coding tools that run shell commands, such as Claude Code and Cursor. It is an MCP client of the same server as the AI assistants, so it can do what they can do, with the same rights. Every tool below works through spaicely call, also the ones without a command of their own.
Install
One file, no runtime needed. Every release has binaries for macOS (Apple silicon and Intel), Linux (x64 and arm64) and Windows (x64), a SHA256SUMS file and a build attestation.
macOS
brew install spaicely/tap/spaicely # or without Homebrew: picks the right binary, checks its SHA-256, puts it in ~/.local/bin curl -fsSL https://spaicely.com/install.sh | sh
Linux
curl -fsSL https://spaicely.com/install.sh | sh # another folder than ~/.local/bin curl -fsSL https://spaicely.com/install.sh | SPAICELY_INSTALL_DIR=/usr/local/bin sh # Homebrew on Linux works too brew install spaicely/tap/spaicely
Windows
In PowerShell, without administrator rights:
$dir = "$env:LOCALAPPDATA\Programs\spaicely"
$zip = "$env:TEMP\spaicely.zip"
$url = "https://github.com/spaicely/cli/releases/latest/download/spaicely-windows-x64.zip"
Invoke-WebRequest $url -OutFile $zip
Expand-Archive $zip -DestinationPath $dir -Force
$path = [Environment]::GetEnvironmentVariable("Path", "User")
[Environment]::SetEnvironmentVariable("Path", "$path;$dir", "User")
Open a new terminal afterwards so it sees the new path. In WSL, use the Linux line above.
With Node.js, on any system
npm install -g spaicely # Node.js 20 or newer npx spaicely whoami # or run it without installing
Check, verify, update
spaicely --version # the download is the build from the repository (needs the GitHub CLI) gh attestation verify spaicely-darwin-arm64.tar.gz --repo spaicely/cli brew upgrade spaicely # Homebrew npm install -g spaicely@latest # npm curl -fsSL https://spaicely.com/install.sh | sh # the script installs the newest release again
Sign in
spaicely login # opens the browser: the same consent screen as for an AI spaicely login --no-browser # over SSH: prints the address to open elsewhere spaicely whoami # who you are, which account, which sites spaicely logout # revokes the sign-in on the server and forgets it here
The sign-in is kept in ~/.config/spaicely/credentials.json, readable only by you. Messages follow the language of your Spaicely account: Dutch, English, German or French.
From folder to live site
spaicely sites create "Bakkerij Jansen" # a new, empty site; or `spaicely sites` for the ones you have cd bakkerij-jansen spaicely init --site 12 # writes spaicely.toml; recognises Jekyll, Hugo, Eleventy, Astro and Vite spaicely serve --build # http://localhost:4000, served the way Spaicely will serve it spaicely deploy --dry-run # what would change compared to the live site spaicely deploy # build, then upload only what changed, as a new version spaicely publish # put the newest version live; asks first spaicely versions # every version, with the one that is live spaicely rollback # back to the version that was live before
spaicely.toml holds what init found; adjust it as you like:
site = 12 # or "bakkerijjansen.nl" dir = "_site" # the folder that goes up build = "bundle exec jekyll build" # runs before deploy and serve --build ignore = ["*.map", "drafts/**"]
In one go, without questions: spaicely deploy --publish --yes. --no-build skips the build, --force uploads even when nothing changed, -d uploads another folder.
Domains and DNS
spaicely domains search bakkerijjansen -e nl,com,eu # no sign-in needed spaicely domains search bakkerijjansen.nl --verify # also asks the registry spaicely domains register bakkerijjansen.nl # shows the price and asks first spaicely domains transfer bakkerijjansen.nl # opens the browser; the transfer code never touches the terminal spaicely domains connect bakkerijjansen.nl --site 12 # shows the records that come along, then the nameservers to set spaicely domains status bakkerijjansen.nl # where the connection stands spaicely dns ls bakkerijjansen.nl spaicely dns add bakkerijjansen.nl TXT @ "google-site-verification=..." spaicely dns add bakkerijjansen.nl MX @ mail.example.com --priority 10 spaicely dns rm bakkerijjansen.nl 31631305 # the number from dns ls
The first registration asks for the registrant's details once: --holder-name, --organization, --email, --phone (with country code), --street, --postal-code, --city and --country. The domain is always registered in the name of your account.
Any tool, and scripts
spaicely tools # every tool the server offers
spaicely call sites.files.list '{"site_id": 12, "prefix": "blog/"}'
spaicely call scripts.enable '{"site_id": 12, "kind": "contact", "name": "Contact"}'
# --json before any command gives machine-readable output
spaicely --json versions | jq '.live'
Exit codes: 0 done, 1 failed, 2 wrong use, 3 not signed in, 5 conflict while publishing. In Windows PowerShell, put the JSON for call in single quotes as well.
In CI
With SPAICELY_TOKEN set, the CLI sends that token instead of the stored sign-in. Make a key for CI in the dashboard under Connected AIs: for one account or one site, it can upload and publish (sites:read content:write sites:publish), works for a year and is shown once. Store it as the secret SPAICELY_TOKEN.
# .github/workflows/deploy.yml
- run: npx spaicely deploy --publish --yes
env:
SPAICELY_TOKEN: ${{ secrets.SPAICELY_TOKEN }}
All commands
| Command | What it does |
|---|---|
login · logout · whoami | Sign in through the browser (--no-browser), forget it, show who you are |
sites · sites create <name> | The sites you can work on; make a new, empty one |
init | Write spaicely.toml for this folder (-s site) |
serve [dir] | Show the site on this machine (-p port, --build) |
deploy | Build and upload a new version (-s, -d, --no-build, --dry-run, --force, --publish, -y) |
publish [version] · rollback · versions | Put a version live, go back one, list them (-s, -y) |
domains search <names...> | Is a name free? (-e extensions, --verify); no sign-in |
domains register · transfer | Register a domain, or move one to Spaicely |
domains connect · status · disconnect | Put a site on its domain (--skip, -y), see where it stands, take it off |
dns ls · dns add · dns rm | The DNS records Spaicely serves for a domain |
tools · call <tool> [json] | Every tool on the server, and calling any of them |
spaicely help <command> shows every option of a command.