The Index Pattern
Separation of concerns without the complexity. Use
index.py for
server-side logic and
index.html for
reactive markup.
index.py
The Controller. Handles database queries, metadata definitions, and heavy lifting. It executes strictly on the server.
- Defines Page Metadata (Title, Desc)
- Fetches Data (Prisma ORM)
- Validates Permissions
index.html
The View. Defines the layout and interactivity using PulsePoint. It receives data implicitly from the Python controller.
- Reactive UI (pp.state, pp.effect)
- Tailwind CSS Styling
- Zero-Build Component Imports
File-System Routing
Routes are defined automatically by your folder structure. A folder
becomes a public URL route if it contains either an
index.html
or an
index.py.
! Routing Hierarchy: Python Takes Precedence
If a folder contains both files, the server designates
index.py as the primary
entry point. The HTML file is ignored by the router and will only be
rendered if the Python script explicitly loads it (e.g., via
load_page(__file__)).
1. The Logic Layer
src/app/index.py
The Python file must export a
page()
function. This is where you define page-specific metadata and load the
view.
from casp.page import load_page # 1. Define Metadata automatically injected into <head> title = "Caspian | The Native Python Web Framework" description = "Build reactive, high-performance web applications." # 2. The entry point function def page(): # Logic goes here (DB calls, Auth checks) return load_page(__file__)
2. The Reactive View
src/app/index.html
The HTML file contains your UI layout. You can import PulsePoint icons,
use Tailwind classes, and write reactive JavaScript directly in
<script>
tags.
<!-- Import Icons or Components --> <!-- @import { Sparkles } from ../../lib/ppicons --> <div class="p-10 text-center space-y-4"> <h1 class="text-4xl font-bold"> Welcome to Caspian </h1> <!-- Reactive Elements --> <button class="btn btn-primary" onclick="handleClick()" > <Sparkles class="mr-2 size-4" /> Click me: {count} </button> </div> <script> // Native Reactivity const [count, setCount] = pp.state(0); function handleClick() { setCount(count + 1); } </script>