SUM Platform CLI: single control plane for site lifecycle management
Project description
SUM CLI (v3.3.3)
The SUM CLI is the single control plane for deploying and managing SUM Platform client sites on staging and production servers.
Install
pip install sum-cli
sum-platform --version
With Gitea Support
If using Gitea instead of GitHub for repository hosting:
pip install sum-cli[gitea]
Initial Setup
Before using the CLI, configure your infrastructure settings:
sudo sum-platform setup
This interactive command creates /etc/sum/config.yml with your staging/production server settings.
Commands
| Command | Description | Requires Sudo |
|---|---|---|
setup |
Configure infrastructure settings | Yes |
init |
Create new site at /srv/sum/<name>/ |
Yes |
update |
Pull updates, migrate, restart | No (staging) |
backup |
PostgreSQL backup via pgBackRest | No |
restore |
Point-in-time database restore | No |
destroy |
Tear down a site and all its infrastructure | Yes |
monitor |
Check backup health, send alerts | No |
promote |
Deploy staging site to production | No |
check |
Validate project setup | No |
theme |
Theme management (list, check, update) | No |
themes |
List themes (deprecated, use theme list) |
No |
Pre-flight Checks
Every state-mutating command (init, promote, backup, restore, update, destroy) runs pre-flight checks before executing. These read-only checks validate that prerequisites are met — missing config files, unreachable servers, and missing tokens are caught before any work begins.
Example Output
Pre-flight checks:
────────────────────────────────────────────────────────────
✅ Site directory: /srv/sum/acme exists
✅ PostgreSQL cluster: Cluster 'acme' is online
✅ SSH connectivity: SSH to 10.0.0.1:22 succeeded
✅ Disk space: 15.2 GB free on /srv/sum
❌ Gitea token: GITEA_TOKEN not set in environment
↳ Fix: Export GITEA_TOKEN or add it to /etc/sum/env
────────────────────────────────────────────────────────────
If any required check fails, the command aborts with actionable fix hints. Recommended checks (e.g., destroy's site existence check) warn but don't block.
Skipping Pre-flight
For automation or CI, bypass checks with the global flag or environment variable:
sum-platform --skip-preflight backup acme
SUM_SKIP_PREFLIGHT=1 sum-platform backup acme
Checks Per Command
| Command | Checks |
|---|---|
init |
SystemConfig, DiskSpace, GiteaToken (if Gitea) |
promote |
SiteExists, PostgresCluster, SSHConnectivity, DiskSpace, GiteaToken + GiteaRepo (if Gitea), CipherPassFile + PgBackRestStanza (if backups) |
backup |
SiteExists, PostgresCluster, CipherPassFile, PgBackRestStanza (if backups configured) |
restore |
SiteExists, PostgresCluster, CipherPassFile, PgBackRestStanza (if backups configured) |
update |
SiteExists, SSHConnectivity (if --target prod) |
destroy |
SiteExists (warning only) |
Theme Management
The theme command group provides tools for managing themes in existing projects.
Listing Themes
# List local themes (from themes/ directory or SUM_THEME_PATH)
sum-platform theme list
# List remote themes from sum-themes repository
sum-platform theme list --remote
Checking for Updates
# Compare current theme version against latest available
cd /path/to/project
sum-platform theme check
Viewing Available Versions
# Show all available versions for a theme
sum-platform theme versions theme_a
Updating Themes
# Update to latest version
cd /path/to/project
sum-platform theme update
# Update to specific version
sum-platform theme update --version 1.2.0
# Allow downgrade to older version
sum-platform theme update --version 1.0.0 --allow-downgrade
# Force reinstall even if at target version
sum-platform theme update --force
Theme updates are atomic with automatic rollback on failure. The lockfile at .sum/theme.json tracks version history.
Site Directory Structure
Each site lives at /srv/sum/<slug>/:
/srv/sum/<slug>/
├── app/ # Django project (git checkout)
├── venv/ # Python virtualenv
├── static/ # collectstatic output
├── media/ # User uploads
└── backups/ # Database backups
Ownership
The CLI runs as root (sudo sum-platform init). After setup, fix_site_ownership() sets the final permissions:
| Directory | Owner | Group | Why |
|---|---|---|---|
app/ |
deploy | www-data | Gunicorn reads code; deploy user runs git pulls |
static/ |
deploy | www-data | collectstatic writes here; Caddy serves directly |
media/ |
deploy | www-data | Django writes uploads here; Caddy serves directly |
venv/ |
root | root | Security — prevents application code from modifying its own runtime |
backups/ |
root | root | Security — prevents application code from accessing/tampering with backups |
The deploy user runs gunicorn, owns application files, and is a member of www-data. It has no sudo access. Configured in /etc/sum/config.yml under defaults.deploy_user.
Operations on site files (app/, static/, media/) should run as the deploy user:
sudo -u deploy /srv/sum/mysite/venv/bin/python /srv/sum/mysite/app/manage.py migrate
sudo -u deploy /srv/sum/mysite/venv/bin/python /srv/sum/mysite/app/manage.py collectstatic
Operations on venv/ and backups/ require root.
Creating Sites
With GitHub
sudo sum-platform init acme --git-provider github --git-org acme-corp
With Gitea
sudo sum-platform init acme --git-provider gitea --git-org clients \
--gitea-url https://gitea.agency.com
With Gitea (Custom SSH Port)
sudo sum-platform init acme --git-provider gitea --git-org clients \
--gitea-url https://gitea.agency.com --gitea-ssh-port 2222
Without Git
sudo sum-platform init acme --no-git
Additional Init Options
sudo sum-platform init acme --git-provider github --git-org acme-corp \
--theme theme_a \
--profile sage-stone \
--content-path /path/to/custom/content
# Skip systemd service installation
sudo sum-platform init acme --no-git --skip-systemd
# Skip Caddy reverse proxy configuration
sudo sum-platform init acme --no-git --skip-caddy
# Set custom Django superuser username (default: admin)
sudo sum-platform init acme --no-git --superuser myuser
Dev / Testing (Unreleased sum-core)
By default, init installs sum-core from a pinned git tag in the boilerplate requirements.txt. To test with unreleased changes, use one of these overrides (listed in priority order):
SUM_CORE_SOURCE environment variable — raw pip requirement line, always takes priority:
SUM_CORE_SOURCE="-e /path/to/local/core" sudo sum-platform init acme --no-git
SUM_CORE_SOURCE="sum-core==0.8.0" sudo sum-platform init acme --no-git
--dev flag — editable install from the monorepo using an absolute path (must run from within the monorepo):
cd /path/to/sum-platform
sudo sum-platform init acme --dev --no-git
--core-ref flag — install from a specific git branch or tag:
sudo sum-platform init acme --core-ref develop --no-git
sudo sum-platform init acme --core-ref feature/my-branch --no-git
--dev and --core-ref are mutually exclusive. SUM_CORE_SOURCE silently overrides both.
Destroying Sites
WARNING: The
destroycommand is irreversible. It permanently removes a site and all its infrastructure.
destroy reverses everything created by init, tearing down resources in safe order:
- Stop and disable the systemd service
- Remove the systemd service file and reload daemon
- Drop the PostgreSQL cluster (and deallocate port)
- Remove pgBackRest stanza config and backup cron
- Remove the Caddy site config and reload
- Remove the site directory (
/srv/sum/<slug>/)
Usage
# Interactive — prompts you to type the site slug to confirm
sudo sum-platform destroy acme
# Skip confirmation prompts (for automation/scripts)
sudo sum-platform destroy acme --force
# Also permanently delete remote backup data
sudo sum-platform destroy acme --purge-backups
Options
| Option | Description |
|---|---|
--force |
Skip all confirmation prompts |
--purge-backups |
Also delete remote backup data via pgBackRest stanza-delete. IRREVERSIBLE. |
Safety Features
- Slug confirmation: You must type the exact site slug to proceed. A mismatch aborts the operation.
- Double confirmation for backups: When
--purge-backupsis used, you must also typeDELETE BACKUPSto confirm. - Path safety check: The command refuses to remove directory paths that don't contain the site slug or are too shallow (prevents accidental deletion of system directories).
- Non-fatal warnings: If individual teardown steps fail (e.g., service already stopped), the command continues and reports warnings rather than aborting.
- Requires root: The command escalates to root privileges automatically.
Recommended: Back Up Before Destroying
# Create a full backup first
sum-platform backup acme --type=full
# Then destroy (without --purge-backups to keep remote backups)
sudo sum-platform destroy acme
Validating Sites
The check command validates that a project is correctly set up and ready to run.
Usage
# Run from inside a project directory
cd /srv/sum/acme/app && sum-platform check
# Or specify a project name (resolves under clients/ directory)
sum-platform check acme
Checks Performed
| Check | What It Validates |
|---|---|
| Virtualenv | Virtual environment exists with required packages (django, wagtail) |
| Credentials | .env.local exists (created during init with superuser credentials) |
| Database | All migrations applied (manage.py migrate --check) |
| Homepage | Homepage is set as the default site root page |
| Theme compiled CSS | Compiled CSS exists at theme/active/static/<slug>/css/main.css and is >5KB |
| Theme slug match | Theme slug in .sum/theme.json matches theme/active/theme.json |
| Required env vars | All keys from .env.example are set in .env or environment |
| sum_core import | sum_core package is importable in the project's Python environment |
Example Output
[OK] Virtualenv: Virtualenv exists with required packages
[OK] Credentials: .env.local found
[OK] Database: Migrations up to date
[OK] Homepage: Homepage set as site root
[OK] Theme compiled CSS: /srv/sum/acme/app/theme/active/static/theme_a/css/main.css
[OK] Theme slug match: theme_a
[OK] Required env vars: Required env vars present
[OK] sum_core import: sum_core importable
✅ All checks passed
Failed checks show remediation hints:
[FAIL] Virtualenv: Package 'django' not installed
→ Run 'pip install -r requirements.txt'
[FAIL] Database: Pending migrations
→ Run 'python manage.py migrate'
The command exits with code 0 on success or 1 if any check fails.
Managing Sites
# Update a deployed site (pull, migrate, restart)
sum-platform update acme
# Update production site
sum-platform update acme --target prod
# Update without running migrations
sum-platform update acme --skip-migrations
# Backup database (PostgreSQL via pgBackRest)
sum-platform backup acme --type full
# Validate project setup
sum-platform check acme
# List available themes
sum-platform theme list
# List remote themes with latest versions
sum-platform theme list --remote
# Check for theme updates in a project
cd /srv/sum/acme && sum-platform theme check
# Update theme to latest version
cd /srv/sum/acme && sum-platform theme update
Promoting to Production
The promote command deploys a working staging site to a production server with a custom domain. It requires a git-enabled site (created without --no-git).
sum-platform promote acme --domain acme-client.com
Options:
| Option | Required | Description |
|---|---|---|
--domain |
Yes | Production domain for the site (e.g., acme-client.com) |
What promote does (11 steps):
- Backs up the staging database
- Copies the backup to the production server via
scp - Provisions production infrastructure (database, user, directories,
.env) - Clones the site repository on production (HTTPS with token, falls back to SSH)
- Creates a virtualenv and installs dependencies
- Restores the database from backup
- Syncs media files from staging via
rsync - Runs Django migrations and
collectstatic - Installs and enables systemd service
- Configures Caddy reverse proxy
- Starts the service and verifies health
After completion, the command prints the production URL and reminds you to configure DNS.
Prerequisites:
- The staging site must exist and have a git repository
- SSH access to the production server must be configured in
/etc/sum/config.yml - The
production.ssh_hostsetting must be set in system config
Backup and Recovery
# Create differential backup
sum-platform backup acme
# Create full backup
sum-platform backup acme --type=full
# List available backups
sum-platform backup acme --list
# List restore points with details
sum-platform restore acme --list
# Restore to specific point in time
sum-platform restore acme --time "2024-01-15 14:30:00"
# Restore to latest backup
sum-platform restore acme --latest
# Clean up pre-restore data after verifying restore
sum-platform restore acme --latest --cleanup
# Skip confirmation prompt (useful for automation)
sum-platform restore acme --latest --confirm
Backup Monitoring
The monitor command checks backup freshness and sends email alerts for stale backups.
# Check all sites, send alerts for problems
sum-platform monitor
# Check without sending alerts
sum-platform monitor --no-alerts
# Verbose output (show all sites)
sum-platform monitor -v
Cron Setup
Add to crontab for hourly monitoring:
0 * * * * /usr/local/bin/sum-platform monitor
Alerts are sent when:
- Backup is older than 48 hours
- Backup status file is missing
Configuration
Global Config (/etc/sum/config.yml)
Infrastructure settings only. Created via sum-platform setup.
agency:
name: Your Agency Name
staging:
server: staging.example.com
domain_pattern: "{slug}.staging.example.com"
base_dir: /srv/sum
production:
server: prod.example.com
ssh_host: 10.0.0.1
base_dir: /srv/sum
templates:
dir: /opt/your-ops/infra
systemd: systemd/sum-site-gunicorn.service.template
caddy: caddy/Caddyfile.template
defaults:
theme: theme_a
seed_profile: starter
deploy_user: deploy
postgres_port: 5432
backups:
storage_box:
host: u123456.your-storagebox.de
user: u123456
fingerprint: SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
port: 23
ssh_key: /etc/sum/backup-key
base_path: /backups
retention:
full_backups: 2
diff_backups: 7
alerts:
email: alerts@agency.com
Site Config (/srv/sum/<site>/.sum/config.yml)
Per-site configuration. Auto-created when you run init.
GitHub site:
site:
slug: acme
theme: theme_a
created: 2026-02-03T14:30:00Z
git:
provider: github
org: acme-corp
Gitea site:
site:
slug: acme
theme: theme_a
created: 2026-02-03T14:30:00Z
git:
provider: gitea
org: clients
url: https://gitea.agency.com
ssh_port: 2222
token_env: GITEA_TOKEN
No-git site:
site:
slug: acme
theme: theme_a
created: 2026-02-03T14:30:00Z
git: null
Git Provider Setup
GitHub
Requires the GitHub CLI (gh) to be installed and authenticated:
gh auth login
Gitea
Set the API token environment variable:
export GITEA_TOKEN=your-token-here
The CLI also detects tokens from the tea CLI config at ~/.config/tea/config.yml as a fallback. If the token is found in the tea config, it is automatically injected into the environment for privilege escalation.
Important: When using --git-provider gitea, the init command warns if no token is detected. The promote command hard-errors — Gitea access is required to clone the repository on production.
Or use a custom environment variable name:
sudo sum-platform init acme --git-provider gitea --git-org clients \
--gitea-url https://gitea.agency.com --gitea-token-env MY_GITEA_TOKEN
Common Workflows
Set Up a New Client Site
# 1. Create the site with git integration
sudo sum-platform init acme --git-provider github --git-org acme-corp
# 2. Validate the setup
sum-platform check acme
# 3. Visit the staging URL shown in init output
Update sum_core on a Deployed Site
# 1. Create a backup before updating
sum-platform backup acme --type=full
# 2. Pull latest code and apply updates
sum-platform update acme
# 3. Verify the site is working
sum-platform check acme
Recover from Backup
# 1. List available restore points
sum-platform restore acme --list
# 2. Restore to the latest backup
sum-platform restore acme --latest
# 3. Verify the restored site
sum-platform check acme
# 4. Clean up pre-restore data once verified
sum-platform restore acme --latest --cleanup
Promote a Staging Site to Production
# 1. Verify the staging site is ready
sum-platform check acme
# 2. Create a full backup before promoting
sum-platform backup acme --type=full
# 3. Promote to production with a custom domain
sum-platform promote acme --domain acme-client.com
# 4. Configure DNS to point to the production server
Destroy a Site Safely
# 1. Create a final backup (in case you need it later)
sum-platform backup acme --type=full
# 2. Destroy the site (keeps remote backups by default)
sudo sum-platform destroy acme
# 3. To also purge remote backup data (irreversible)
sudo sum-platform destroy acme --purge-backups
Troubleshooting
"Database configuration required" error
The .env file is missing or incomplete.
cp .env.example .env
# Edit .env with your database credentials
make db-up && make dev-reset
check reports "sum_core import" failure
The sum_core package is not installed in the site's virtualenv.
cd /srv/sum/acme
source venv/bin/activate
pip install sum-core
destroy warns "Could not stop service"
The systemd service may already be stopped or never created (e.g., if --skip-systemd was used during init). This warning is non-fatal — the command continues removing other resources.
promote fails with "Cannot promote without git repository"
The staging site was created with --no-git. Promote requires a git repository to clone on the production server. Re-create the site with a git provider.
init fails with permission errors
The init command requires root. Run with sudo:
sudo sum-platform init acme --no-git
Backup/restore fails with pgBackRest errors
Ensure pgBackRest is installed and the stanza is initialized:
# Check pgBackRest info for the site
sudo -u postgres pgbackrest --stanza=acme info
If the stanza doesn't exist, it was likely not created during init. Re-running init is the safest fix.
Development Install (monorepo)
pip install -e ./cli
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sum_cli-3.3.3.tar.gz.
File metadata
- Download URL: sum_cli-3.3.3.tar.gz
- Upload date:
- Size: 264.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
607039012d213f6bb804570a5fbcc52ba03036ad8301831390eac39a82532d8a
|
|
| MD5 |
bedfee8812b43bff2ec669dd44ec4705
|
|
| BLAKE2b-256 |
55ec13c4cbb07cbc09054f4ef7b0a7864d7cdc05262ff5e86d5d2f14cacbd9f3
|
File details
Details for the file sum_cli-3.3.3-py3-none-any.whl.
File metadata
- Download URL: sum_cli-3.3.3-py3-none-any.whl
- Upload date:
- Size: 186.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
24c58c72530d378963c91adc8a4c4d74f83ed606d4ac6d21885fbce462f29dca
|
|
| MD5 |
bebf7be5f465617551e6101a7e32a70b
|
|
| BLAKE2b-256 |
c66acc2b63500d42e14a92eddfc71bb74c79c157211ccfa0b7698d75a8e75fab
|