Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol. wisp.place
1# Wisp CLI 2 3A command-line tool for deploying static sites to your AT Protocol repo to be served on [wisp.place](https://wisp.place), an AT indexer to serve such sites. 4 5## Why? 6 7The PDS serves as a way to verfiably, cryptographically prove that you own your site. That it was you (or at least someone who controls your account) who uploaded it. It is also a manifest of each file in the site to ensure file integrity. Keeping hosting seperate ensures that you could move your site across other servers or even serverless solutions to ensure speedy delievery while keeping it backed by an absolute source of truth being the manifest record and the blobs of each file in your repo. 8 9## Features 10 11- Deploy static sites directly to your AT Protocol repo 12- Supports both OAuth and app password authentication 13- Preserves directory structure and file integrity 14 15## Soon 16 17-- Host sites 18-- Manage and delete sites 19-- Metrics and logs for self hosting. 20 21## Installation 22 23### From Source 24 25```bash 26cargo build --release 27``` 28 29Check out the build scripts for cross complation using nix-shell. 30 31The binary will be available at `target/release/wisp-cli`. 32 33## Usage 34 35### Basic Deployment 36 37Deploy the current directory: 38 39```bash 40wisp-cli nekomimi.ppet --path . --site my-site 41``` 42 43Deploy a specific directory: 44 45```bash 46wisp-cli alice.bsky.social --path ./dist/ --site my-site 47``` 48 49### Authentication Methods 50 51#### OAuth (Recommended) 52 53By default, the CLI uses OAuth authentication with a local loopback server: 54 55```bash 56wisp-cli alice.bsky.social --path ./my-site --site my-site 57``` 58 59This will: 601. Open your browser for authentication 612. Save the session to a file (default: `/tmp/wisp-oauth-session.json`) 623. Reuse the session for future deployments 63 64Specify a custom session file location: 65 66```bash 67wisp-cli alice.bsky.social --path ./my-site --site my-site --store ~/.wisp-session.json 68``` 69 70#### App Password 71 72For headless environments or CI/CD, use an app password: 73 74```bash 75wisp-cli alice.bsky.social --path ./my-site --site my-site --password YOUR_APP_PASSWORD 76``` 77 78**Note:** When using `--password`, the `--store` option is ignored. 79 80## Command-Line Options 81 82``` 83wisp-cli [OPTIONS] <INPUT> 84 85Arguments: 86 <INPUT> Handle (e.g., alice.bsky.social), DID, or PDS URL 87 88Options: 89 -p, --path <PATH> Path to the directory containing your static site [default: .] 90 -s, --site <SITE> Site name (defaults to directory name) 91 --store <STORE> Path to auth store file (only used with OAuth) [default: /tmp/wisp-oauth-session.json] 92 --password <PASSWORD> App Password for authentication (alternative to OAuth) 93 -h, --help Print help 94 -V, --version Print version 95``` 96 97## How It Works 98 991. **Authentication**: Authenticates using OAuth or app password 1002. **File Processing**: 101 - Recursively walks the directory tree 102 - Skips hidden files (starting with `.`) 103 - Detects MIME types automatically 104 - Compresses files with gzip 105 - Base64 encodes compressed content 1063. **Upload**: 107 - Uploads files as blobs to your PDS 108 - Processes up to 5 files concurrently 109 - Creates a `place.wisp.fs` record with the site manifest 1104. **Deployment**: Site is immediately available at `https://sites.wisp.place/{did}/{site-name}` 111 112## File Processing 113 114All files are automatically: 115 116- **Compressed** with gzip (level 9) 117- **Base64 encoded** to bypass PDS content sniffing 118- **Uploaded** as `application/octet-stream` blobs 119- **Stored** with original MIME type metadata 120 121The hosting service automatically decompresses non HTML/CSS/JS files when serving them. 122 123## Limitations 124 125- **Max file size**: 100MB per file (after compression) (this is a PDS limit, but not enforced by the CLI in case yours is higher) 126- **Max file count**: 2000 files 127- **Site name** must follow AT Protocol rkey format rules (alphanumeric, hyphens, underscores) 128 129## Deploy with CI/CD 130 131### GitHub Actions 132 133```yaml 134name: Deploy to Wisp 135on: 136 push: 137 branches: [main] 138 139jobs: 140 deploy: 141 runs-on: ubuntu-latest 142 steps: 143 - uses: actions/checkout@v3 144 145 - name: Setup Node 146 uses: actions/setup-node@v3 147 with: 148 node-version: '25' 149 150 - name: Install dependencies 151 run: npm install 152 153 - name: Build site 154 run: npm run build 155 156 - name: Download Wisp CLI 157 run: | 158 curl -L https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-x86_64-linux -o wisp-cli 159 chmod +x wisp-cli 160 161 - name: Deploy to Wisp 162 env: 163 WISP_APP_PASSWORD: ${{ secrets.WISP_APP_PASSWORD }} 164 run: | 165 ./wisp-cli alice.bsky.social \ 166 --path ./dist \ 167 --site my-site \ 168 --password "$WISP_APP_PASSWORD" 169``` 170 171### Tangled.org 172 173```yaml 174when: 175 - event: ['push'] 176 branch: ['main'] 177 - event: ['manual'] 178 179engine: 'nixery' 180 181clone: 182 skip: false 183 depth: 1 184 submodules: false 185 186dependencies: 187 nixpkgs: 188 - nodejs 189 - coreutils 190 - curl 191 github:NixOS/nixpkgs/nixpkgs-unstable: 192 - bun 193 194environment: 195 SITE_PATH: 'dist' 196 SITE_NAME: 'my-site' 197 WISP_HANDLE: 'your-handle.bsky.social' 198 199steps: 200 - name: build site 201 command: | 202 export PATH="$HOME/.nix-profile/bin:$PATH" 203 204 # regenerate lockfile 205 rm package-lock.json bun.lock 206 bun install @rolldown/binding-linux-arm64-gnu --save-optional 207 bun install 208 209 # build with vite 210 bun node_modules/.bin/vite build 211 212 - name: deploy to wisp 213 command: | 214 # Download Wisp CLI 215 curl https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-x86_64-linux -o wisp-cli 216 chmod +x wisp-cli 217 218 # Deploy to Wisp 219 ./wisp-cli \ 220 "$WISP_HANDLE" \ 221 --path "$SITE_PATH" \ 222 --site "$SITE_NAME" \ 223 --password "$WISP_APP_PASSWORD" 224``` 225 226### Generic Shell Script 227 228```bash 229# Use app password from environment variable 230wisp-cli alice.bsky.social --path ./dist --site my-site --password "$WISP_APP_PASSWORD" 231``` 232 233## Output 234 235Upon successful deployment, you'll see: 236 237``` 238Deployed site 'my-site': at://did:plc:abc123xyz/place.wisp.fs/my-site 239Available at: https://sites.wisp.place/did:plc:abc123xyz/my-site 240``` 241 242### Dependencies 243 244- **jacquard**: AT Protocol client library 245- **clap**: Command-line argument parsing 246- **tokio**: Async runtime 247- **flate2**: Gzip compression 248- **base64**: Base64 encoding 249- **walkdir**: Directory traversal 250- **mime_guess**: MIME type detection 251 252## License 253 254MIT License 255 256## Contributing 257 258Just don't give me entirely claude slop especailly not in the PR description itself. You should be responsible for code you submit and aware of what it even is you're submitting. 259 260## Links 261 262- **Website**: https://wisp.place 263- **Main Repository**: https://tangled.org/@nekomimi.pet/wisp.place-monorepo 264- **AT Protocol**: https://atproto.com 265- **Jacquard Library**: https://tangled.org/@nonbinary.computer/jacquard 266 267## Support 268 269For issues and questions: 270- Check the main wisp.place documentation 271- Open an issue in the main repository