Wisp CLI v1.1.0
Deploy static sites to the AT Protocol
The Wisp CLI is a command-line tool for deploying static websites directly to your AT Protocol account. Host your sites on wisp.place with full ownership and control, backed by the decentralized AT Protocol.
Jump to: Features · Downloads · CI/CD · Basic Usage · Authentication · File Processing · Incremental Updates · Limits · Command Reference · Development
Features
Section titled “Features”- Deploy: Push static sites directly from your terminal
- Pull: Download sites from the PDS for development or backup
- Serve: Run a local server with real-time firehose updates
- Private sites: Upload access-controlled sites and manage share links
- Authenticate with app password or OAuth
- Incremental updates: Only upload changed files
Recommended Install
Section titled “Recommended Install”npm install -g wispctl@latest
Downloads
Section titled “Downloads”Download v1.3.1
macOS (Apple Silicon): wisp-cli-aarch64-darwin
macOS (Intel): wisp-cli-x86_64-darwin
Linux (ARM64): wisp-cli-aarch64-linux
Linux (x86_64): wisp-cli-x86_64-linux
Windows (x86_64): wisp-cli-x86_64-windows.exe
SHA-256 Checksums
ed3b5d82291fd955ade565780837844d67eba60869948f1ec1e78fa810f30a70 wisp-cli-aarch64-darwin
11b911d957480731974c6aa6a7ac274c8ec64074a0886bd095596d77dce58196 wisp-cli-x86_64-darwin
4402c7688d7e318b4d62fe132ec9ac67db368b24c01d987d736c7558e3fa2f2c wisp-cli-darwin-universal
3fc6ce46f7d07b5b55a59d5fc2f648ec446e25fc1e0475f92de51eb0a361eec2 wisp-cli-aarch64-linux
e60bb9025c12dad7a1e4c53da58638737b7bc35c5e560aa3cf913573b2b8eb9f wisp-cli-x86_64-linux
5372c0ad37f2b925853d1fb1c9d9c85fbd4fbfbc11d58671cd084394e7584bdc wisp-cli-x86_64-windows.exe
note: the tool used to be named wisp-cli and downloadable binaries are kept this way to preseve compatibility with CI
CI/CD Integration
Section titled “CI/CD Integration”Deploy automatically on every push using Tangled Spindle:
when: - event: ['push'] branch: ['main'] - event: ['manual']
engine: 'nixery'
dependencies: nixpkgs: - nodejs - coreutils - curl - glibc github:NixOS/nixpkgs/nixpkgs-unstable: - bun
environment: SITE_PATH: 'dist' SITE_NAME: 'my-site' WISP_HANDLE: 'your-handle.bsky.social'
steps: - name: build site command: | export PATH="$HOME/.nix-profile/bin:$PATH"
# you may need to regenerate the lockfile due to nixery being weird # rm package-lock.json bun.lock bun install
bun run build
- name: deploy to wisp command: | # Download Wisp CLI curl https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-x86_64-linux -o wisp-cli chmod +x wisp-cli
# Deploy to Wisp ./wisp-cli \ "$WISP_HANDLE" \ --path "$SITE_PATH" \ --site "$SITE_NAME"Note: Set WISPCTL_APP_PASSWORD as a secret in your Tangled Spindle repository settings.
The CLI reads it directly from the environment, keeping the app password out of the process
arguments. Generate an app password from your AT Protocol account settings.
Basic Usage
Section titled “Basic Usage”Deploy a Site
Section titled “Deploy a Site”# Download and make executablecurl -O https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-aarch64-darwinchmod +x wisp-cli-aarch64-darwin
# Deploy your sitewispctl deploy your-handle.bsky.social \ --path ./dist \ --site my-siteYour site will be available at: https://sites.wisp.place/your-handle/my-site
Domain Management
Section titled “Domain Management”# Claim a custom domainwispctl domain claim your-handle.bsky.social --domain example.com
# Claim a subdomainwispctl domain claim-subdomain your-handle.bsky.social --subdomain alice
# Check domain statuswispctl domain status your-handle.bsky.social --domain example.com
# Attach a site to a domainwispctl domain add-site your-handle.bsky.social --domain example.com --site mysite
# Delete a domain or sitewispctl domain delete your-handle.bsky.social --domain example.comwispctl site delete your-handle.bsky.social --site mysiteList Domains & Sites
Section titled “List Domains & Sites”wispctl list domains your-handle.bsky.socialwispctl list sites your-handle.bsky.socialOptions
Section titled “Options”Use an alternate proxy service DID:
wispctl list domains your-handle.bsky.social --service did:web:example.comPull a Site from PDS
Section titled “Pull a Site from PDS”Download a site from the PDS to your local machine:
# Pull a site to a specific directorywispctl pull your-handle.bsky.social \ --site my-site \ --path ./my-site
# Pull to current directorywispctl pull your-handle.bsky.social \ --site my-siteServe a Site Locally with Real-Time Updates
Section titled “Serve a Site Locally with Real-Time Updates”Run a local server that monitors the firehose for real-time updates:
# Serve on http://localhost:8080 (default)wispctl serve your-handle.bsky.social \ --site my-site
# Serve on a custom portwispctl serve your-handle.bsky.social \ --site my-site \ --port 3000
# Enable SPA mode (serve index.html for all routes)wispctl serve your-handle.bsky.social \ --site my-site \ --spa
# Enable directory listing for paths without index fileswispctl serve your-handle.bsky.social \ --site my-site \ --directoryDownloads site, serves it, and watches firehose for live updates!
Authentication
Section titled “Authentication”Credentials are stored once and shared across every directory. Handles are remembered per
directory, so after the first login a bare wispctl deploy in that folder just works.
OAuth (Recommended)
Section titled “OAuth (Recommended)”wispctl login your-handle.bsky.socialThis opens your browser and stores the session in your OS keychain (macOS Keychain, Windows
Credential Manager, or the Secret Service on Linux), keyed by DID. Running
wispctl deploy your-handle.bsky.social from any other directory reuses that stored session
instead of opening the browser again.
If no OS credential store is available, OAuth sessions fall back to a local SQLite file at
~/.config/wispctl/state.sqlite and the CLI warns you.
App Password
Section titled “App Password”For headless environments or CI/CD, use an app password:
wispctl deploy your-handle.bsky.social \ --path ./dist \ --site my-site \ --password YOUR_APP_PASSWORDTo avoid putting the secret in the command line (where it is visible in the process table),
set WISPCTL_APP_PASSWORD instead:
export WISPCTL_APP_PASSWORD=YOUR_APP_PASSWORDwispctl deploy your-handle.bsky.social --path ./dist --site my-siteThe environment variable is used whenever a handle is given; with no handle the CLI falls back to your stored accounts as usual.
You can also save an app password to the keychain so you do not have to supply it each time:
WISPCTL_APP_PASSWORD=YOUR_APP_PASSWORD wispctl login your-handle.bsky.socialApp passwords are only ever written to the OS credential store — unlike short-lived OAuth tokens they are never written to the SQLite fallback. On a machine without a keychain, the login still works but the password is not saved.
Generate app passwords from your AT Protocol account settings.
Managing Accounts
Section titled “Managing Accounts”# List stored accounts, their credentials, and which directories are linkedwispctl accounts
# Pick the account used in directories with no linked accountwispctl accounts use your-handle.bsky.social
# Unlink the current directory (stored credentials stay put)wispctl logout
# Forget one account everywhere, including its stored credentialswispctl logout your-handle.bsky.social
# Forget everythingwispctl logout --allA bare command with no handle resolves in this order: the account linked to the current
directory, then the account chosen with wispctl accounts use, then your only stored account
if you have exactly one. With several accounts and no explicit choice, the CLI prompts rather
than guessing which identity to deploy as.
File Processing
Section titled “File Processing”The CLI handles all file processing automatically to ensure reliable storage and delivery. Files are compressed with gzip at level 9 for optimal size reduction, then base64 encoded to bypass PDS content sniffing restrictions. Everything is uploaded as application/octet-stream blobs while preserving the original MIME type as metadata. When serving your site, the hosting service automatically decompresses non-HTML/CSS/JS files, ensuring your content is delivered correctly to visitors.
File Filtering: The CLI automatically excludes common files like .git, node_modules, .env, and other development artifacts. Customize this with a .wispignore file.
Incremental Updates
Section titled “Incremental Updates”The CLI tracks file changes using CID-based content addressing to minimize upload times and bandwidth usage. On your first deploy, all files are uploaded to establish the initial site. For subsequent deploys, the CLI compares content-addressed CIDs to detect which files have actually changed, uploading only those that differ from the previous version. This makes fast iterations possible even for large sites, with deploys completing in seconds when only a few files have changed.
Limits
Section titled “Limits”- Max file size: 100MB per file (after compression)
- Max total size: 300MB per site
- Max files: 1000 files per site
- Site name: Must follow AT Protocol rkey format (alphanumeric, hyphens, underscores)
Command Reference
Section titled “Command Reference”Deploy Command
Section titled “Deploy Command”wispctl deploy [OPTIONS] [HANDLE]
Arguments: [HANDLE] Handle (e.g., alice.bsky.social) or DID. Optional once an account is stored.
Options: -p, --path <PATH> Path to site directory [default: .] -s, --site <SITE> Site name (defaults to directory name) --password <PASSWORD> App password for authentication --db <PATH> Account database path [default: ~/.config/wispctl/state.sqlite] -h, --help Print helpPull Command
Section titled “Pull Command”wispctl pull [OPTIONS] --site <SITE> <INPUT>
Arguments: <INPUT> Handle or DID
Options: -s, --site <SITE> Site name to download -p, --path <PATH> Output directory [default: .] -h, --help Print helpServe Command
Section titled “Serve Command”wispctl serve [OPTIONS] --site <SITE> <INPUT>
Arguments: <INPUT> Handle or DID
Options: -s, --site <SITE> Site name to serve -p, --path <PATH> Site files directory [default: .] -P, --port <PORT> Port to serve on [default: 8080] --spa Enable SPA mode (serve index.html for all routes) --directory Enable directory listing mode for paths without index files -h, --help Print help- place.wisp.fs - Site manifest lexicon
- place.wisp.subfs - Subtree records for large sites
- AT Protocol - The decentralized protocol powering Wisp