Capuzzella ships a CLI that wraps its HTTP API into shell commands. It's a thin client — no local state, no config files, no database connections. Every command is an authenticated HTTP request to a running Capuzzella server. This post covers setup and every command group.
Setup
The CLI is available as an npm package. Install it globally with:
npm install -g capuzzella
This makes the capuzzella command available system-wide. The package
is published at
npmjs.com/package/capuzzella.
You can also run it directly without installing:
npx capuzzella <command>
The CLI requires Node.js 18 or later (for native fetch support) and has
zero dependencies.
Two environment variables control the CLI:
| Variable | Required | Default | Purpose |
|---|---|---|---|
CAPUZZELLA_API_KEY |
Yes | — | Bearer token for API authentication |
CAPUZZELLA_URL |
No | http://localhost:3000 |
Base URL of the Capuzzella server |
If CAPUZZELLA_API_KEY is not set, the CLI exits immediately with a
helpful message. Trailing slashes on CAPUZZELLA_URL are stripped
automatically. There is no config file, no .capuzzellarc, no
capuzzella.config.js. Environment variables are the only input.
Start by pointing the CLI at your Capuzzella instance. Most deployments run on
Render, so the URL will look like
https://your-instance.onrender.com. Export it in your shell:
export CAPUZZELLA_URL=https://your-instance.onrender.com
The default is http://localhost:3000, which is only useful during
local development. If you're running against a deployed instance, you
must set CAPUZZELLA_URL — otherwise every
command will fail with a connection error.
Next, get an API key. Open Settings → API Keys in the
Capuzzella admin UI and create a new key. The key starts with cap_
and is shown only once — copy it immediately. Then export it:
export CAPUZZELLA_API_KEY=cap_your_key_here
To persist both variables across sessions, add the export lines to your shell
profile (~/.zshrc, ~/.bashrc, or equivalent). In CI
environments, store them as secrets and inject them at runtime. You can also pass
both inline for a single command:
CAPUZZELLA_URL=https://your-instance.onrender.com CAPUZZELLA_API_KEY=cap_your_key_here capuzzella whoami
Command Groups
The CLI organizes its commands into eight groups: identity, pages, publishing, scheduling, key management, AI provider configuration, transactional emails, and custom domains. Each group maps directly to a section of the REST API.
Identity
capuzzella whoami
Calls GET /api/me and prints the role, key name, key ID, and
associated email for the current API key. Useful for verifying which key is active
in your shell session, especially when switching between environments.
Pages
Page paths are always relative and end in .html. Nested paths use
forward slashes: blog/post.html, services/consulting.html.
| Command | API Call | Description |
|---|---|---|
pages list |
GET /api/pages |
Lists all draft pages as JSON |
pages get <path> |
GET /api/pages/<path> |
Prints the raw HTML of a page |
pages save <path> --file <file> |
PUT /api/pages/<path> |
Reads a local file and uploads it as a page |
pages delete <path> |
DELETE /api/pages/<path> |
Deletes both the draft and published copy |
pages get detects whether the response contains an html
field and prints raw HTML if so, otherwise falls back to pretty-printed JSON. This
makes it easy to pipe page content into other tools:
capuzzella pages get index.html > backup.html
pages save requires the --file flag. It reads the file
from disk using Node's fs module, checks that the file exists,
and sends the contents as the html field in a JSON body. This is a
create-or-update operation — if the page path doesn't exist, it's created;
if it does, it's overwritten.
Publishing
Capuzzella's content model is built on two directories: drafts/ and
public/. Publishing copies a page from drafts to public. Unpublishing
removes the public copy while keeping the draft intact.
| Command | API Call | Description |
|---|---|---|
publish all |
POST /publish/ |
Publishes every draft at once |
publish <path> |
POST /publish/<path> |
Publishes a single page |
unpublish <path> |
DELETE /publish/<path> |
Removes the published copy |
status <path> |
GET /publish/status/<path> |
Shows isPublished and hasUnpublishedChanges |
The status command is the one you'll reach for most often. It returns
two booleans: whether the page is currently published, and whether the draft has
diverged from the published version. A typical workflow looks like:
capuzzella pages save blog/post.html --file ./post.html
capuzzella status blog/post.html
capuzzella publish blog/post.html
Scheduled Publishing
Scheduled publishing lets you queue a page to go live at a specific time. The server stores schedules in SQLite and runs a background check to publish pages when their scheduled time arrives.
| Command | API Call | Description |
|---|---|---|
schedule list |
GET /publish/schedule?status=pending |
Lists pending schedules |
schedule list all |
GET /publish/schedule |
Lists all schedules (including completed and cancelled) |
schedule add <path> --at <datetime> |
POST /publish/schedule |
Schedules a page for future publish |
schedule get <id> |
GET /publish/schedule/<id> |
Gets details of a scheduled publish |
schedule cancel <id> |
DELETE /publish/schedule/<id> |
Cancels a pending schedule |
The --at flag takes an ISO 8601 datetime string. Timestamps are stored
as Unix epoch seconds internally, but the CLI converts them back to ISO format for
display. The schedule list output shows each schedule on a single line:
capuzzella schedule add blog/launch.html --at 2026-04-01T09:00:00Z
# Scheduled #3: blog/launch.html will publish at 2026-04-01T09:00:00.000Z
capuzzella schedule list
# #3 blog/launch.html → 2026-04-01T09:00:00.000Z [pending]
API Key Management
These commands require an admin-role API key. They let you manage access to the Capuzzella API without touching the server's admin UI.
| Command | API Call | Description |
|---|---|---|
keys list |
GET /settings/api-keys |
Lists all API keys (hashed, not plaintext) |
keys create --name <n> --role <r> [--rate-limit <n>] |
POST /settings/api-keys |
Creates a key and prints it once |
keys revoke <id> |
POST /settings/api-keys/<id>/revoke |
Revokes a key (disables without deleting) |
keys delete <id> |
POST /settings/api-keys/<id>/delete |
Permanently deletes a key |
keys audit <id> |
GET /settings/api-keys/<id>/audit |
Shows the request audit log for a key |
When creating a key, the plaintext value (prefixed cap_) is printed
exactly once. The server stores only the hash. If you lose it, you create a new one.
The --role flag accepts editor, admin,
viewer, or designer. The --rate-limit flag
defaults to 60 requests per minute if omitted.
capuzzella keys create --name "CI pipeline" --role editor --rate-limit 120
# API key created. Copy it now — it will not be shown again:
# cap_abc123...
Revoking a key is a soft disable — the key record stays but stops authenticating. Deleting is permanent. Both are useful in different situations: revoke when you suspect a leak and want to investigate, delete when cleaning up old integrations.
The keys audit command shows the request log for a specific key —
every API call it has made, with timestamp, HTTP method, and path. This is useful
for debugging integrations and reviewing what an agent or script has been doing:
capuzzella keys audit 3
# 2026-03-16T10:23:45.000Z GET /api/pages
# 2026-03-16T10:23:46.000Z PUT /api/pages/index.html
# 2026-03-16T10:23:47.000Z POST /publish/index.html
AI Provider Configuration
These commands let you view and change the AI provider settings (which model powers the built-in AI editor) from the command line. Admin-role API key required.
| Command | API Call | Description |
|---|---|---|
ai-provider get |
GET /settings/ai-provider |
Shows the active provider, available models, and configuration status |
ai-provider set --provider <id> [--model <m>] [--api-key <k>] |
POST /settings/ai-provider |
Sets the active provider, model, and/or API key |
The supported providers are openai and anthropic. Each
provider has its own list of models (e.g. gpt-5.4,
claude-sonnet-4-6). You can switch providers and models without
touching the server's admin UI:
capuzzella ai-provider get
# Active provider: openai
# openai (OpenAI) [active, configured]
# Model: gpt-5.4
# Available: gpt-5.4, gpt-5-mini, gpt-4.1, gpt-4.1-mini, ...
# anthropic (Anthropic)
# Model: claude-sonnet-4-6
# Available: claude-opus-4-6, claude-sonnet-4-6, ...
capuzzella ai-provider set --provider anthropic --model claude-sonnet-4-6 --api-key sk-ant-...
# AI provider set to anthropic, model: claude-sonnet-4-6
The --api-key flag is only needed when configuring a provider for the
first time or rotating a key. If the provider already has a key saved, you can omit
it and just switch the model.
Transactional Emails
Capuzzella uses Resend for sending invitation emails, magic-link logins, password resets, and contact form notifications. These commands manage the Resend configuration.
| Command | API Call | Description |
|---|---|---|
email get |
GET /settings/resend |
Shows the current email configuration |
email set --domain <d> --contact-email <e> [--api-key <k>] |
POST /settings/resend |
Configures Resend for transactional emails |
email remove |
POST /settings/resend |
Removes the Resend configuration entirely |
capuzzella email set --domain mail.example.com --contact-email admin@example.com --api-key re_xxxxx
# Email configured: domain=mail.example.com, contact=admin@example.com
capuzzella email get
# Transactional email configuration:
# Domain: mail.example.com
# Contact Email: admin@example.com
The --domain is the verified sending domain in your Resend account
(used as the From address). The --contact-email is where
contact form submissions are forwarded. Removing the configuration disables all
email features — invitations, magic links, and password resets will stop
working.
Custom Domains
If your Capuzzella instance runs on Render, you can manage custom domains from the CLI. These commands interact with the Render API to add, list, and remove domains.
| Command | API Call | Description |
|---|---|---|
domains list |
GET /settings/custom-domains |
Lists all custom domains with verification status |
domains add <domain> |
POST /settings/custom-domains |
Adds a custom domain |
domains delete <domain-id> |
DELETE /settings/custom-domains/<id> |
Removes a custom domain |
capuzzella domains add example.com
# Custom domain added: example.com
# Configure a CNAME or A record at your DNS provider to complete setup.
capuzzella domains list
# example.com [pending] id: cdm-abc123
# www.example.com [verified] id: cdm-def456
capuzzella domains delete cdm-abc123
# Custom domain removed.
After adding a domain, you need to configure DNS at your domain provider. Subdomains
require a CNAME record pointing to your .onrender.com hostname. Apex
domains require an A record pointing to 216.24.57.1. TLS certificates
are provisioned automatically once DNS verification passes.
Scripting and CI Integration
Because every command returns structured JSON and exits with code 0 on success or 1 on failure, the CLI slots into shell scripts and CI pipelines naturally:
#!/bin/bash
set -e
# Deploy all HTML files from a build directory
for file in dist/*.html; do
page=$(basename "$file")
capuzzella pages save "$page" --file "$file"
capuzzella publish "$page"
echo "Published $page"
done
In a GitHub Actions workflow, you'd set CAPUZZELLA_API_KEY and
CAPUZZELLA_URL as repository secrets, install the CLI with
npm install -g capuzzella, and run your deployment script. The CLI's
stateless design means there's no setup step beyond exporting two environment
variables.
Full Command Reference
Run capuzzella --help (or capuzzella with no arguments)
to print the built-in reference:
Capuzzella CLI
Usage: capuzzella <command> [options]
Commands:
whoami Show current key role and identity
pages list List all pages
pages get <path> Get page HTML
pages save <path> --file <file> Save page from local file
pages delete <path> Delete a page
publish all Publish all drafts
publish <path> Publish a single page
unpublish <path> Unpublish a page
status <path> Check publish status
schedule list List pending scheduled publishes
schedule list all List all scheduled publishes
schedule add <path> --at <datetime> Schedule a page for future publish
schedule get <id> Get details of a scheduled publish
schedule cancel <id> Cancel a pending scheduled publish
keys list List API keys
keys create --name <n> --role <r> Create a new API key
keys revoke <id> Revoke an API key
keys delete <id> Delete an API key
keys audit <id> Show audit log for an API key
ai-provider get Show AI provider configuration
ai-provider set --provider <id> Set active AI provider
[--model <model>] [--api-key <key>]
email get Show transactional email config
email set --domain <d> Configure transactional emails
--contact-email <e> [--api-key <k>]
email remove Remove transactional email config
domains list List custom domains
domains add <domain> Add a custom domain
domains delete <domain-id> Remove a custom domain
Environment:
CAPUZZELLA_API_KEY API key (required)
CAPUZZELLA_URL Server URL (default: http://localhost:3000)