- Python 97%
- PowerShell 1.7%
- Shell 1.3%
|
|
||
|---|---|---|
| .forgejo/workflows | ||
| scms | ||
| .gitignore | ||
| .gitkeep | ||
| app.py | ||
| config-example.yml | ||
| docker-compose.pylon.yml | ||
| Dockerfile.pylon | ||
| pyproject.toml | ||
| README.md | ||
| requirements.txt | ||
| setup.ps1 | ||
| setup.sh | ||
SCMS
Simple Content Management Service is a CLI tool for publishing bundles of Markdown files and static media, called content packages, to a remote Pylon server. Webservers are intended to consume the index JSON and Markdown files from the Pylon for rendering.
Quickstart
scms publish <prefix> # Publish a content package
scms publish <prefix> --force # Force publish (even if no changes detected)
scms publish <prefix> --shadow # Shadow publish a content package
scms unpublish <prefix> # Unpublish a content package
scms pull <prefix> # Pull a content package from a Pylon
scms pull --all # Pull every package from the Pylon
scms packages # List all published packages on a Pylon
scms pylon start # Run SCMS in Pylon Mode
scms pylon index # Rebuild the index on all configured Pylons
scms pylon show # List configured Pylon connectors
scms pylon show "<pylon-name>" # Show remote Pylon configuration
Installation
Local setup
Linux/macOS:
curl -fsSL https://git.eriksonarias.dev/eriksonarias/scms/raw/branch/main/setup.sh | bash
Windows (PowerShell):
irm https://git.eriksonarias.dev/eriksonarias/scms/raw/branch/main/setup.ps1 | iex
The scripts install SCMS via pipx (no virtual environment required), create a content/ directory, and run the interactive config wizard.
Upadting
After installation, SCMS can be updated with the update command.
scms update
Development
Create a virtual environment and install requirements:
# Create a virtual environment
python -m venv venv
# Activate virtual environment
source venv/bin/activate # Linux/macOS
.\venv\Scripts\Activate.ps1 # Windows
# Install requirements
python -m pip install -r requirements.txt
Configure SCMS by creating a config.yml file (see config-example.yml for a complete example).
Configuration
Client configuration
Each profile on the client side configures one or more Pylon connectors, which distributes content to its own connectors server-side.
profiles:
default:
connectors:
- name: my pylon
url: https://host:port
token: abcdefg
profile: default # Optional, Pylon-side profile to use
ignore:
- content/wip
Profiles
Profiles let you switch between environments (e.g. development vs production) at the command line. A profile called default is required.
All commands can take a --profile argument.
scms publish <prefix> --profile <profile-name>
scms publish <prefix> -p <profile-name>
Pylon server configuration
The pylon top-level key configures Pylon Mode (the server). The server's own connectors and post-hooks are configured under pylon.profiles:
pylon:
token: abcdefg # Required. Generate with: openssl rand -hex 32
host: 0.0.0.0 # Optional. Default: 0.0.0.0
port: 8000 # Optional. Default: 8000
store_files: true # Optional. Store uploaded files on the Pylon server. Default: false
profile: default # Optional. Default server-side profile to use
index_directory: index # Optional. Where to store index files. Default: index
profiles:
default:
connectors:
- name: minio
type: s3
host: example.com:9000
access_key: abcd
secret_key: efgh
bucket: content
destination: content # Optional prefix within bucket
post_hooks:
- name: Ping website
type: rest
url: http://example.com/content-load
ignore:
- content/wip
Ignores
Directories can be excluded from indexing and publishing. Useful for work-in-progress content:
profiles:
default:
ignore:
- content/wip
- content/drafts
Content packages
Content packages (or simply packages) are directories of files that SCMS manages as a single unit. A package is identified by the presence of a .scms.yml file in its directory.
content/
├─ posts/
│ ├─ my-first-post/
│ │ ├─ my-first-post.md
│ │ └─ .scms.yml
│ └─ another-post/
│ ├─ another-post.md
│ └─ .scms.yml
└─ about-me/
├─ about-me.md
└─ .scms.yml
The three packages above have IDs:
posts/my-first-postposts/another-postabout-me
Creating a package
Create a subdirectory under content/ with a .scms.yml file (may be empty). Each package should have at most one Markdown file named identically to its directory (e.g. my-article/my-article.md).
Publishing
scms publish <prefix>
scms publish <prefix> --force # Force publish, even if no files have changed
scms publish <prefix> -f
Publishes all packages matching the given prefix to all configured Pylons. Only new or modified files are uploaded by default; deleted files are propagated to the Pylon automatically.
Prefixes
A prefix selects one or more packages. Use / or an empty string to publish everything:
scms publish / # All packages
scms publish posts/ # All packages under posts/
scms publish posts/my-first-post # One specific package
Shadow publishing
scms publish <prefix> --shadow
scms publish <prefix> -s
Pushes content with a shadow flag. Shadow-published content is included in the shadow index but excluded from the public index. Whether shadow content is rendered is at the discretion of the consuming webserver.
Bypassing prompts
Some commands such as publish will affect multiple packages and display a prompt to continue execution.
Use -Y to skip confirmation prompts (useful for scripting):
scms publish / -Y
scms unpublish <prefix> -Y
scms pull <prefix> -Y
Unpublishing
scms unpublish <prefix>
Removes all files for matching packages from the Pylon (and its connectors) and removes them from the index. The local content directory is not affected; republishing later will treat the content as new.
Pulling
scms pull <prefix>
Downloads a content package from the Pylon back into the local content/ directory. Useful for syncing content to a new machine or recovering files. If files already exist locally, a confirmation prompt is shown (bypass with -Y).
scms pull --all
scms pull -a
All content packages can be pulled using the --all flag.
Listing packages
scms packages
scms packages --shadow # Include shadow-published packages
scms packages -p <profile>
Lists all packages on the configured Pylon, showing package ID, status (published/shadow), file count, publish date, and connectors.
Index
scms index
scms index --force-rebuild
Builds or updates the SQLite index database and JSON index files for all Pylons:
{profile}-index.jsonfor published, non-shadow packages only{profile}-shadow-index.jsonfor all published packages including shadow
Pylon
Pylon is the SCMS server component. All publishing is routed through a Pylon; the client never writes directly to connectors (S3, FTP, etc.).
When configured, a Pylon:
- Receives uploaded packages from the client.
- Distributes files to its own configured connectors.
- Maintains a SQLite index and exports JSON index files.
- Runs post-hooks after every publish or unpublish.
Running Pylon Mode
scms pylon start
scms pylon start --host 0.0.0.0 --port 8000
Or with Docker:
docker compose -f docker-compose.pylon.yml up -d
Pylon endpoints
| Method | Path | Description |
|---|---|---|
GET |
/health |
Health check (unauthenticated) |
POST |
/publish |
Upload and publish a content package |
POST |
/unpublish |
Remove a content package and update the index |
GET |
/pull |
Download a package as a zip |
GET |
/index |
Return the JSON index |
GET |
/packages |
List all packages with status and connector info |
GET |
/config |
Return the active server configuration (redacted) |
PUT |
/content |
Upload a single file |
DELETE |
/content |
Delete a file or directory |
POST |
/hooks |
Run post-hooks |
Inspecting a Pylon
scms pylon show # List all configured Pylon connectors
scms pylon show "<pylon-name>" # Show Pylon server-side config
scms pylon show "<pylon-name>" -p <profile>