The Capuzzella CLI: A Complete Guide

Maurice Wipf · March 12, 2026

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)