The Python web framework for building apps.
Originally a fork of Django, reshaped over years of real use. Ready for the era of agents.
Start with an agent (Claude, Codex, Amp, OpenCode, or your agent of choice):
mkdir my-app && cd my-app && claude "$(curl -sSf https://plainframework.com/start.md)"
Or start with uv directly:
uvx plain-start my-app
Full walkthrough: https://plainframework.com/start/
Explicit, typed, and predictable. What's good for humans is good for AI.
Models are Postgres-only:
# app/users/models.py
from plain import postgres
from plain.postgres import types
from plain.passwords.models import PasswordField
@postgres.register_model
class User(postgres.Model):
email: str = types.EmailField()
password: str = PasswordField()
display_name: str = types.TextField(max_length=100)
is_admin: bool = types.BooleanField(default=False)
created_at: datetime = types.DateTimeField(create_now=True)
query: postgres.QuerySet[User] = postgres.QuerySet()
model_options = postgres.Options(
constraints=[
postgres.UniqueConstraint(fields=["email"], name="unique_email"),
],
)URLs use a Router class:
# app/users/urls.py
from plain.urls import Router, path
from . import views
class UsersRouter(Router):
namespace = "users"
urls = [
path("<int:pk>/", views.UserDetail),
]Views are class-based:
# app/users/views.py
from plain.views import DetailView
from .models import User
class UserDetail(DetailView):
template_name = "users/detail.html"
def get_object(self):
return User.query.get(pk=self.url_kwargs["pk"])Templates are Jinja:
{# app/users/templates/users/detail.html #}
{% extends "base.html" %}
{% block content %}
<h1>{{ user.display_name }}</h1>
<p>Joined {{ user.created_at.strftime("%B %Y") }}</p>
{% endblock %}Python where you want it, JS where you need it.
- Python: 3.13+
- Database: Postgres
- Templates: Jinja2
- Frontend: htmx, Tailwind CSS
- Python tooling: uv (packages), ruff (lint/format), ty (type checking)
- JavaScript tooling: oxc (lint/format), esbuild (bundling)
- Testing: pytest
Models declare fields as annotated attributes, and that typing carries through views, forms, and URLs. plain check runs ty on every pass β what your IDE shows, CI enforces, and agents read from the same signatures.
OpenTelemetry traces, a built-in request observer, and slow-query detection ship in the box. The first time an N+1 matters, you already have the tools to see it.
Predictable APIs, typed signatures, and on-demand docs happen to be what both people and coding agents need. Plain projects also ship tooling that agents use automatically.
Rules β Always-on guardrails stored in project rules files (e.g. .claude/rules/ for Claude Code). Short files (~50 lines) that prevent the most common mistakes.
Docs β Full framework documentation, accessible on demand from the command line:
plain docs models # full docs
plain docs models --api # typed signatures only
plain docs models --search "queryset" # just the sections matching a term
plain docs --search "queryset" # search across all packages
Skills β End-to-end workflows triggered by slash commands:
/plain-installβ add a new package and walk through setup/plain-upgradeβ bump versions, read changelogs, apply breaking changes, run checks/plain-optimizeβ capture performance traces, identify slow queries and N+1 problems, apply fixes/plain-bugβ collect context and submit a bug report as a GitHub issue
32 packages, one framework. All with built-in docs. Decisions that usually take a sprint are already made.
Foundation:
- plain β core framework
- plain.postgres β database ORM
- plain.auth β authentication
- plain.sessions β session storage
Backend:
- plain.api β REST APIs
- plain.mcp β MCP server for AI clients
- plain.jobs β background jobs
- plain.email β sending email
- plain.cache β caching layer
- plain.redirection β URL redirects
- plain.vendor β vendored dependencies
Frontend:
- plain.htmx β dynamic UI
- plain.tailwind β CSS framework
- plain.elements β HTML components
- plain.pages β static pages
- plain.esbuild β JS bundling
Development:
- plain.dev β local server
- plain.pytest β testing helpers
- plain.toolbar β debug toolbar
- plain.code β code formatting
- plain.portal β remote shell and file transfer
- plain.tunnel β dev tunneling
- plain.start β project starter
Production:
- plain.admin β database admin
- plain.observer β request tracing
- plain.connect β OTLP export to Plain Cloud
- plain.flags β feature flags
- plain.scan β security scanning
- plain.pageviews β analytics
- plain.support β support tickets
Users:
- plain.passwords β password auth
- plain.oauth β social login
- plain.loginlink β magic links
Plain is a fork of Django, started in the stone age of 2023 and driven by real use at PullApprove.
- Docs: https://plainframework.com/docs/
- Source: https://github.com/dropseed/plain
- Getting started: https://plainframework.com/start/
- License: BSD-3