# 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: 1. **Explain available options first** - Present different approaches to solve the problem 2. **Wait for validation** - Ensure mutual understanding of requirements before implementation 3. **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:** ```python 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:** 1. **Explain the problem clearly first** 2. **Do not propose a fix immediately** 3. **Wait for validation** that the diagnosis is correct 4. 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_xxx` patterns ### `/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 ```bash # 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 ```bash # 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 ```bash # 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 integration - `Command`: Standard command that executes a Python callable - `LambdaCommand`: Inline command for simple operations - `CommandsManager`: Global registry for command execution **How commands work:** 1. Create command with action: `cmd = Command("name", "description", callable)` 2. Command auto-registers with `CommandsManager` 3. `cmd.get_htmx_params()` generates HTMX attributes (`hx-post`, `hx-vals`) 4. HTMX posts to `/myfasthtml/commands` route with `c_id` 5. `CommandsManager` routes to correct command's `execute()` method **Command customization:** ```python # 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:** 1. User changes input → HTMX posts to `/myfasthtml/bindings` 2. `Binding.update()` receives form data, updates observable object 3. Observable triggers change event → `Binding.notify()` 4. All bound UI elements update via HTMX swap-oob **Helper usage:** ```python 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 `name` attribute to trigger updates - Multiple elements can bind to same data attribute - First binding call uses `init_binding=True` to set initial value - Bindings route through `/myfasthtml/bindings` endpoint ### Core System: Instances Session-scoped instance management system. Located in `src/myfasthtml/core/instances.py`. **Key classes:** - `BaseInstance`: Base for all managed instances - `SingleInstance`: One instance per parent per session - `UniqueInstance`: One instance ever per session (singleton-like) - `RootInstance`: Top-level singleton for application - `InstancesManager`: Global registry with session-based isolation **Instance creation pattern:** ```python # __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` ```python 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:** 1. Adds MyFastHtml CSS/JS assets via custom static route 2. Optionally adds DaisyUI 5 + Tailwind CSS 4 3. Optionally adds vis-network.js 4. Mounts `/myfasthtml` app for commands and bindings routes 5. Optionally sets up auth routes and beforeware 6. 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 protection - `auth/routes.py`: Login, register, logout routes - `auth/pages/`: LoginPage, RegisterPage, WelcomePage components **How auth works:** 1. Beforeware checks `access_token` in session before each route 2. Auto-refreshes token if < 5 minutes to expiry 3. Redirects to `/login` if token invalid/missing 4. Protected routes receive `auth` parameter with user info **Session structure:** ```python { '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 route - `user.find_element(selector)`: Find element by CSS selector - `user.should_see(text)`: Assert text in response - Returns `TestableElement` objects 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:** ```python 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 ```python 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 ```python 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) ```python # 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 1. **Bindings require `name` attribute**: Without it, form data won't include the field 2. **Commands auto-register**: Don't manually register with CommandsManager 3. **Instances use __new__ caching**: Same (session, id) returns existing instance 4. **First binding needs init**: Use `init_binding=True` to set initial value 5. **Observable required for bindings**: Use `make_observable()` from myutils 6. **Auth routes need base_url**: Pass `base_url` to `create_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