Skip to content

ZechCodes/Skrift

Repository files navigation

Skrift

Python 3.12+ License: MIT Built with Litestar

A modern Litestar-powered content management framework with multi-provider OAuth authentication, role-based access control, and WordPress-like template resolution.

Features

  • Multi-Provider OAuth: Authenticate with Google, GitHub, Microsoft, Discord, Facebook, or Twitter/X
  • Role-Based Access Control: Flexible permission system with Admin, Editor, Author, and Moderator roles
  • Setup Wizard: Guided first-time configuration without manual file editing
  • Admin Interface: Web-based management for users, pages, and site settings
  • WordPress-like Templates: Hierarchical template resolution for content pages
  • Dynamic Controllers: Load controllers from app.yaml configuration
  • SQLAlchemy Integration: Async database support with SQLite/PostgreSQL
  • Client-Side Sessions: Encrypted cookie sessions for horizontal scalability
  • Hook/Filter System: WordPress-like extensibility with async support
  • SEO Metadata: Built-in meta descriptions, OpenGraph tags, and robots directives
  • Content Scheduling: Schedule pages to publish at a future date
  • Page Revisions: Automatic content history with restore capability
  • Sitemap & Robots.txt: Auto-generated with filter extensibility

Quick Start

Prerequisites

  • Python 3.13+

Installation

# Install Skrift
pip install skrift

# Or install from git
pip install git+https://github.com/ZechCodes/skrift.git

Getting Started

Create a project directory and set up your environment:

mkdir mysite && cd mysite

# Create minimal environment file
echo "SECRET_KEY=$(python -c 'import secrets; print(secrets.token_urlsafe(32))')" > .env

# Start Skrift
skrift

Open http://localhost:8080 to launch the setup wizard.

Setup Wizard

The setup wizard guides you through initial configuration:

  1. Database Configuration: Choose SQLite (dev) or PostgreSQL (production)
  2. Authentication Providers: Configure OAuth credentials
  3. Site Settings: Set site name, tagline, and copyright info
  4. Admin Account: Create your first admin user via OAuth login

After completing the wizard, an app.yaml configuration file is created in your project directory.

Manual Configuration

Alternatively, create app.yaml manually:

controllers:
  - skrift.controllers.auth:AuthController
  - skrift.admin.controller:AdminController
  - skrift.controllers.web:WebController

db:
  url: sqlite+aiosqlite:///./app.db

auth:
  redirect_base_url: http://localhost:8080
  providers:
    google:
      client_id: $GOOGLE_CLIENT_ID
      client_secret: $GOOGLE_CLIENT_SECRET
      scopes: [openid, email, profile]

Then run migrations and start the server:

skrift-db upgrade head
skrift

Documentation

Project Structure

skrift/
├── skrift/              # Main Python package
│   ├── asgi.py          # Application factory
│   ├── config.py        # Settings management
│   ├── controllers/     # Route handlers (auth, web, sitemap)
│   ├── admin/           # Admin panel
│   ├── auth/            # RBAC and guards
│   ├── db/              # Models and services
│   │   ├── models/      # Page, User, Role, PageRevision
│   │   └── services/    # page_service, revision_service
│   ├── lib/             # Core utilities
│   │   ├── hooks.py     # Hook/filter system
│   │   ├── seo.py       # SEO metadata utilities
│   │   ├── flash.py     # Enhanced flash messages
│   │   └── template.py  # Template resolver
│   └── setup/           # Setup wizard
├── templates/           # Jinja2 templates
├── static/              # Static assets
├── alembic/             # Database migrations
├── docs/                # Documentation
├── app.yaml             # Application config (generated)
└── main.py              # Development entry point

Configuration

Environment Variables

Variable Required Description
SECRET_KEY Yes Session encryption key
DEBUG No Enable debug mode (default: false)
DATABASE_URL No Database connection string
OAUTH_REDIRECT_BASE_URL No OAuth callback base URL

OAuth credentials are configured per-provider (e.g., GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET).

app.yaml

Application configuration is stored in app.yaml (generated by setup wizard):

controllers:
  - skrift.controllers.auth:AuthController
  - skrift.admin.controller:AdminController
  - skrift.controllers.web:WebController

db:
  url: $DATABASE_URL
  pool_size: 5

auth:
  redirect_base_url: $OAUTH_REDIRECT_BASE_URL
  providers:
    google:
      client_id: $GOOGLE_CLIENT_ID
      client_secret: $GOOGLE_CLIENT_SECRET

Environment variables (prefixed with $) are interpolated at runtime.

Deployment

Minimal VPS Deployment

# Install Skrift
pip install skrift

# Create project directory
mkdir -p /opt/skrift && cd /opt/skrift

# Configure environment
cat > .env << EOF
SECRET_KEY=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
DATABASE_URL=sqlite+aiosqlite:///./app.db
OAUTH_REDIRECT_BASE_URL=https://yourdomain.com
EOF

# Start server (use setup wizard or create app.yaml manually)
skrift

Production with Hypercorn

hypercorn skrift.asgi:app --workers 4 --bind 0.0.0.0:8080

See the Deployment Guide for detailed instructions including Docker, Docker Compose, and Kubernetes deployments.

Database Migrations

# Apply migrations
skrift-db upgrade head

# Create new migration
skrift-db revision --autogenerate -m "description"

# Rollback
skrift-db downgrade -1

Template Resolution

Templates follow WordPress-like hierarchical resolution:

URL Path Templates Tried
/about page-about.html -> page.html
/services/web page-services-web.html -> page-services.html -> page.html

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Submit a pull request

License

MIT

About

A lightweight CMS built with Litestar and SQLAlchemy

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors