14 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
MyFastHtml is a Python utility library that simplifies FastHTML application development by providing:
- Command management system for client-server interactions
- Bidirectional data binding system
- Predefined authentication pages and routes
- Interactive control helpers
- Session-based instance management
Tech Stack: Python 3.12+, FastHTML, HTMX, DaisyUI 5, Tailwind CSS 4
Development Workflow and Guidelines
Development Process
Code must always be testable. Before writing any code:
- Explain available options first - Present different approaches to solve the problem
- Wait for validation - Ensure mutual understanding of requirements before implementation
- No code without approval - Only proceed after explicit validation
Collaboration Style
Ask questions to clarify understanding or suggest alternative approaches:
- Ask questions one at a time
- Wait for complete answer before asking the next question
- Indicate progress: "Question 1/5" if multiple questions are needed
- Never assume - always clarify ambiguities
Communication
Conversations: French or English Code, documentation, comments: English only
Code Standards
Follow PEP 8 conventions strictly:
- Variable and function names:
snake_case - Explicit, descriptive naming
- No emojis in code
Documentation:
- Use Google or NumPy docstring format
- Document all public functions and classes
- Include type hints where applicable
Dependency Management
When introducing new dependencies:
- List all external dependencies explicitly
- Propose alternatives using Python standard library when possible
- Explain why each dependency is needed
Unit Testing with pytest
Test naming patterns:
- Passing tests:
test_i_can_xxx- Tests that should succeed - Failing tests:
test_i_cannot_xxx- Edge cases that should raise errors/exceptions
Test structure:
- Use functions, not classes (unless inheritance is required)
- Before writing tests, list all planned tests with explanations
- Wait for validation before implementing tests
Example:
def test_i_can_create_command_with_valid_name():
"""Test that a command can be created with a valid name."""
cmd = Command("valid_name", "description", lambda: None)
assert cmd.name == "valid_name"
def test_i_cannot_create_command_with_empty_name():
"""Test that creating a command with empty name raises ValueError."""
with pytest.raises(ValueError):
Command("", "description", lambda: None)
File Management
Always specify the full file path when adding or modifying files:
✅ Modifying: src/myfasthtml/core/commands.py
✅ Creating: tests/core/test_new_feature.py
Error Handling
When errors occur:
- Explain the problem clearly first
- Do not propose a fix immediately
- Wait for validation that the diagnosis is correct
- Only then propose solutions
Available Personas
This project includes specialized personas (slash commands) for different types of work:
/developer - Development Mode (Default)
Use for: Writing code, implementing features, fixing bugs
Activates the full development workflow with:
- Options-first approach before coding
- Step-by-step validation
- Strict PEP 8 compliance
- Test-driven development with
test_i_can_xxx/test_i_cannot_xxxpatterns
/technical-writer - Documentation Mode
Use for: Writing user-facing documentation
Focused on creating:
- README sections and examples
- Usage guides and tutorials
- Getting started documentation
- Code examples for end users
Does NOT handle:
- Docstrings (developer responsibility)
- Internal architecture docs
- CLAUDE.md updates
/reset - Default Claude Code
Use for: Return to standard Claude Code behavior without personas
Development Commands
Testing
# Run all tests
pytest
# Run specific test file
pytest tests/core/test_bindings.py
# Run specific test
pytest tests/core/test_bindings.py::test_function_name
# Run tests with verbose output
pytest -v
Cleaning
# Clean build artifacts and cache
make clean
# Clean package distribution files
make clean-package
# Clean test artifacts (.sesskey, test databases)
make clean-tests
# Clean everything including source artifacts
make clean-all
Package Building
# Build distribution
python -m build
# Install in development mode
pip install -e .
Architecture Overview
Core System: Commands
Commands abstract HTMX interactions by encapsulating server-side actions. Located in src/myfasthtml/core/commands.py.
Key classes:
BaseCommand: Base class for all commands with HTMX integrationCommand: Standard command that executes a Python callableLambdaCommand: Inline command for simple operationsCommandsManager: Global registry for command execution
How commands work:
- Create command with action:
cmd = Command("name", "description", callable) - Command auto-registers with
CommandsManager cmd.get_htmx_params()generates HTMX attributes (hx-post,hx-vals)- HTMX posts to
/myfasthtml/commandsroute withc_id CommandsManagerroutes to correct command'sexecute()method
Command customization:
# Change HTMX target and swap
cmd.htmx(target="#result", swap="innerHTML")
# Bind to observable data (disables swap by default)
cmd.bind(data_object)
Core System: Bindings
Bidirectional data binding system connects UI components with Python data objects. Located in src/myfasthtml/core/bindings.py.
Key concepts:
- Observable objects: Use
make_observable()from myutils to enable change detection - Three-phase lifecycle: Create → Activate (bind_ft) → Deactivate
- Detection modes: How changes are detected (ValueChange, AttributePresence, SelectValueChange)
- Update modes: How UI updates (ValueChange, AttributePresence, SelectValueChange)
- Data converters: Transform data between UI and Python representations
Binding flow:
- User changes input → HTMX posts to
/myfasthtml/bindings Binding.update()receives form data, updates observable object- Observable triggers change event →
Binding.notify() - All bound UI elements update via HTMX swap-oob
Helper usage:
from myfasthtml.controls.helpers import mk
# Bind input and label to same data
input_elt = Input(name="field")
label_elt = Label()
mk.manage_binding(input_elt, Binding(data, "attr"))
mk.manage_binding(label_elt, Binding(data, "attr"))
Important binding notes:
- Elements MUST have a
nameattribute to trigger updates - Multiple elements can bind to same data attribute
- First binding call uses
init_binding=Trueto set initial value - Bindings route through
/myfasthtml/bindingsendpoint
Core System: Instances
Session-scoped instance management system. Located in src/myfasthtml/core/instances.py.
Key classes:
BaseInstance: Base for all managed instancesSingleInstance: One instance per parent per sessionUniqueInstance: One instance ever per session (singleton-like)RootInstance: Top-level singleton for applicationInstancesManager: Global registry with session-based isolation
Instance creation pattern:
# __new__ checks registry before creating
# If instance exists with same (session_id, _id), returns existing
instance = MyInstance(parent, session, _id="optional")
Automatic ID generation:
- SingleInstance:
snake_case_class_name - UniqueInstance:
snake_case_class_name - Regular BaseInstance:
parent_prefix-uuid
Application Setup
Main entry point: create_app() in src/myfasthtml/myfastapp.py
from myfasthtml.myfastapp import create_app
app, rt = create_app(
daisyui=True, # Include DaisyUI CSS
vis=True, # Include vis-network.js
protect_routes=True, # Enable auth beforeware
mount_auth_app=False, # Mount auth routes
base_url=None # Base URL for auth
)
What create_app does:
- Adds MyFastHtml CSS/JS assets via custom static route
- Optionally adds DaisyUI 5 + Tailwind CSS 4
- Optionally adds vis-network.js
- Mounts
/myfasthtmlapp for commands and bindings routes - Optionally sets up auth routes and beforeware
- Creates AuthProxy instance if auth enabled
Authentication System
Located in src/myfasthtml/auth/. Integrates with FastAPI backend (myauth package).
Key components:
auth/utils.py: JWT helpers, beforeware for route protectionauth/routes.py: Login, register, logout routesauth/pages/: LoginPage, RegisterPage, WelcomePage components
How auth works:
- Beforeware checks
access_tokenin session before each route - Auto-refreshes token if < 5 minutes to expiry
- Redirects to
/loginif token invalid/missing - Protected routes receive
authparameter with user info
Session structure:
{
'access_token': 'jwt_token',
'refresh_token': 'refresh_token',
'user_info': {
'email': 'user@example.com',
'username': 'user',
'roles': ['admin'],
'id': 'uuid',
'created_at': 'timestamp',
'updated_at': 'timestamp'
}
}
Project Structure
src/myfasthtml/
├── myfastapp.py # Main app factory (create_app)
├── core/
│ ├── commands.py # Command system
│ ├── bindings.py # Binding system
│ ├── instances.py # Instance management
│ ├── utils.py # Utilities, routes app
│ ├── constants.py # Routes, constants
│ ├── dbmanager.py # Database helpers
│ ├── AuthProxy.py # Auth proxy instance
│ └── network_utils.py # Network utilities
├── controls/
│ ├── helpers.py # mk class with UI helpers
│ ├── BaseCommands.py # Base command implementations
│ ├── Search.py # Search control
│ └── Keyboard.py # Keyboard shortcuts
├── auth/
│ ├── utils.py # JWT, beforeware
│ ├── routes.py # Auth routes
│ └── pages/ # Login, Register, Welcome pages
├── icons/ # Icon libraries (fluent, material, etc.)
├── assets/ # CSS/JS files
└── test/ # Test utilities
tests/
├── core/ # Core system tests
├── testclient/ # TestClient and TestableElement tests
├── auth/ # Authentication tests
├── controls/ # Control tests
└── html/ # HTML component tests
Testing System
Custom test client: myfasthtml.test.TestClient extends FastHTML test client
Key features:
user.open(path): Navigate to routeuser.find_element(selector): Find element by CSS selectoruser.should_see(text): Assert text in response- Returns
TestableElementobjects with component-specific methods
Testable element types:
TestableInput:.send(value)TestableCheckbox:.check(),.uncheck(),.toggle()TestableTextarea:.send(value),.append(text),.clear()TestableSelect:.select(value),.select_by_text(text),.deselect(value)TestableRange:.set(value),.increase(),.decrease()TestableRadio:.select()TestableButton:.click()TestableDatalist:.send(value),.select_suggestion(value)
Test pattern:
def test_component(user, rt):
@rt("/")
def index():
data = Data("initial")
component = Component(name="field")
label = Label()
mk.manage_binding(component, Binding(data))
mk.manage_binding(label, Binding(data))
return component, label
user.open("/")
user.should_see("initial")
elem = user.find_element("selector")
elem.method("new_value")
user.should_see("new_value")
Important Patterns
Creating interactive buttons with commands
from myfasthtml.controls.helpers import mk
from myfasthtml.core.commands import Command
def action():
return "Result"
cmd = Command("action", "Description", action)
button = mk.button("Click", command=cmd)
Bidirectional binding
from myutils.observable import make_observable
from myfasthtml.core.bindings import Binding
from myfasthtml.controls.helpers import mk
data = make_observable(Data("value"))
input_elt = Input(name="field")
label_elt = Label()
mk.manage_binding(input_elt, Binding(data, "value"))
mk.manage_binding(label_elt, Binding(data, "value"))
Using helpers (mk class)
# Button with command
mk.button("Text", command=cmd, cls="btn-primary")
# Icon with command
mk.icon(icon_svg, size=20, command=cmd)
# Label with icon
mk.label("Text", icon=icon_svg, size="sm")
# Generic wrapper
mk.mk(element, command=cmd, binding=binding)
Common Gotchas
- Bindings require
nameattribute: Without it, form data won't include the field - Commands auto-register: Don't manually register with CommandsManager
- Instances use new caching: Same (session, id) returns existing instance
- First binding needs init: Use
init_binding=Trueto set initial value - Observable required for bindings: Use
make_observable()from myutils - Auth routes need base_url: Pass
base_urltocreate_app()for proper auth API calls
Dependencies
Core:
- python-fasthtml: Web framework
- myauth: Authentication backend
- mydbengine: Database abstraction
- myutils: Observable pattern, utilities
UI:
- DaisyUI 5: Component library
- Tailwind CSS 4: Styling
- vis-network: Network visualization
Development:
- pytest: Testing framework
- httpx: HTTP client for tests
- python-dotenv: Environment variables