ship-kit

Production-ready SaaS toolkit for FastHTML applications - simple utilities, not frameworks

Overview

Launch Kit provides composable utilities for building production-ready SaaS applications with FastHTML. Following Answer.AI’s philosophy of simplicity and transparency, it offers pre-built functionality without hiding the underlying framework.

Core Principles: - 🎯 No Magic - Everything is explicit and inspectable - 🧩 Composable - Import only what you need - 🔍 Transparent - You can see exactly what’s happening - ⚡ FastHTML-First - Enhances FastHTML, doesn’t wrap it - 🎨 Override-Friendly - Sensible defaults, full customization

Installation

Install latest from the GitHub repository:

pip install git+https://github.com/LotsOfOrg/ship-kit.git

Or install from PyPI (when available):

pip install ship-kit

For development:

# Clone the repository
git clone https://github.com/LotsOfOrg/ship-kit.git
cd ship-kit

# Install in development mode
pip install -e .

# Install with development dependencies
pip install -e ".[dev]"

Quick Start

Basic FastHTML App with Authentication

Here’s how to add authentication to your FastHTML app in minutes:

from fasthtml.common import *
from ship_kit.routes.auth import login_route, signup_route, logout_route

# Standard FastHTML app - no wrapping!
app, rt = fast_app()

# Add authentication routes with one line each
login_route(app)
signup_route(app) 
logout_route(app)

# Your routes - that's it!
@rt("/")
def get(sess):
    user = sess.get('auth')
    if user:
        return Title("Home"), Main(
            H1(f"Welcome {user['email']}!"),
            A("Logout", href="/auth/logout")
        )
    return Title("Welcome"), Main(
        P("Please ", A("login", href="/auth/login"), " to continue.")
    )

serve()

That’s it! You now have: - 📝 Beautiful login and signup forms with MonsterUI - 🔐 Secure password hashing - 🍪 Session-based authentication - 🚀 HTMX-enhanced interactions - 🎨 Fully customizable components

Features

🔐 Authentication Module

Core authentication utilities and pre-built routes:

from ship_kit.auth import hash_password, verify_password

Password hashing utilities

password = “secure_password123” hashed = hash_password(password) print(f”Hashed: {hashed[:20]}…“)

Verification

is_valid = verify_password(password, hashed) print(f”Valid: {is_valid}“)

Wrong password

is_valid = verify_password(“wrong_password”, hashed) print(f”Invalid: {not is_valid}“)

🛤️ Pre-built Routes

Customizable authentication routes that follow FastHTML patterns:

# Customize any aspect of the routes
from monsterui.all import *

def my_login_form(error=None, **kwargs):
    return Container(
        Card(
            H1("Welcome Back!", cls="text-3xl font-bold mb-6"),
            Form(
                LabelInput("Email", name="email", type="email", required=True),
                LabelInput("Password", name="password", type="password", required=True),
                Alert(error, variant="destructive") if error else None,
                Button("Sign In", type="submit", cls="w-full", size="lg"),
                method="post",
                cls="space-y-4"
            ),
            cls="max-w-md mx-auto"
        ),
        cls="min-h-screen flex items-center"
    )

# Use your custom form
login_route(app, login_form=my_login_form)

Coming Soon

Launch Kit is under active development. Upcoming features include:

  • 🛡️ Permissions & RBAC - Role-based access control decorators
  • 👨‍💼 Admin Panel - Customizable admin interface utilities
  • 👥 Team Management - Multi-tenant team functionality
  • 💳 Billing Integration - Stripe and payment utilities
  • 🚦 Middleware - Rate limiting, CSRF protection
  • 📊 API Management - API key generation and validation
  • 🔍 Search - Full-text search utilities
  • 📤 Data Export - CSV/JSON export helpers

Philosophy: Utilities, Not Frameworks

Launch Kit follows Answer.AI’s principles:

  1. Simple things should be simple - login_route(app) just works
  2. Complex things should be possible - Override any component or behavior
  3. No magic - You can read and understand every line of code
  4. Composable - Use only what you need, ignore the rest
  5. FastHTML-native - Uses standard FastHTML patterns (rt, sess, FT components)

Advanced Example: Custom Authentication

Here’s how to build a complete authentication system with custom logic:

from fasthtml.common import *
from ship_kit.auth import hash_password, verify_password
from ship_kit.routes.auth import login_route, signup_route, logout_route
from datetime import datetime

# Your database setup (example with dict for simplicity)
users_db = {}

def authenticate_user(email, password):
    """Custom authentication logic"""
    user = users_db.get(email)
    if user and verify_password(password, user['password_hash']):
        return {'email': email, 'name': user['name']}
    return None

def create_user(form_data):
    """Custom user creation logic"""
    email = form_data.get('email')
    
    # Validation
    if form_data['password'] != form_data['password_confirm']:
        return "Passwords don't match"
    
    if email in users_db:
        return "Email already registered"
    
    # Create user
    users_db[email] = {
        'name': form_data['name'],
        'password_hash': hash_password(form_data['password']),
        'created_at': datetime.now()
    }
    
    return {'email': email, 'name': form_data['name']}

# Create app with session middleware
app, rt = fast_app(
    secret_key='your-secret-key',  # Required for sessions
    pico=True  # Optional: Use Pico CSS for styling
)

# Add auth routes with custom logic
login_route(app, authenticate=authenticate_user)
signup_route(app, create_user=create_user)
logout_route(app)

# Protected route example
@rt("/dashboard")
def get(sess):
    user = sess.get('auth')
    if not user:
        return RedirectResponse('/auth/login', status_code=303)
    
    return Title("Dashboard"), Main(
        H1(f"Welcome to your dashboard, {user['name']}!"),
        P(f"Logged in as: {user['email']}"),
        Button("Logout", hx_get="/auth/logout", hx_push_url="true")
    )

# Public route
@rt("/")
def get():
    return Title("Ship Kit Demo"), Main(
        H1("Welcome to Ship Kit"),
        P("A FastHTML toolkit for building SaaS applications"),
        Div(
            A("Login", href="/auth/login", cls="button"),
            " ",
            A("Sign Up", href="/auth/signup", cls="button outline"),
            cls="grid"
        )
    )

serve()

Developer Guide

Launch Kit uses nbdev for development. Here’s how to contribute:

Development Setup

# Clone the repository
git clone https://github.com/LotsOfOrg/ship-kit.git
cd ship-kit

# Install in development mode
pip install -e .

# Make changes in the notebooks under nbs/
# The source code in ship_kit/ is auto-generated

# After making changes, prepare for commit
nbdev_prepare

Project Structure

ship-kit/
├── nbs/                    # Development notebooks (source of truth)
│   ├── 00_auth.ipynb      # Core authentication utilities
│   ├── 01_routes_auth.ipynb # Authentication routes
│   └── index.ipynb        # This file (package docs)
├── ship_kit/            # Auto-generated Python modules
│   ├── auth.py
│   └── routes/
│       └── auth.py
└── settings.ini          # nbdev configuration

Important: Never edit files in ship_kit/ directly - they’re auto-generated from notebooks!

Documentation

  • GitHub: https://github.com/LotsOfOrg/ship-kit
  • Documentation: https://LotsOfOrg.github.io/ship-kit/
  • Issues: https://github.com/LotsOfOrg/ship-kit/issues

License

Licensed under the Apache License, Version 2.0. See LICENSE for details.

How to use

Launch Kit provides simple, transparent utilities for building production-ready FastHTML applications. Here’s a quick example of using the authentication utilities:

from ship_kit.auth import hash_password, verify_password

# Hash a password when user signs up
password = "secure_password123"
hashed = hash_password(password)
print(f"Hashed: {hashed[:20]}...")

# Verify password when user logs in
is_valid = verify_password(password, hashed)
print(f"Valid: {is_valid}")