|
| 1 | +# Coding Agent Guidelines |
| 2 | + |
| 3 | +Reflex: Python web **framework** compiling to React. Monorepo using uv workspace — main package in `reflex/`, sub-packages in `packages/`, docs site in `docs/`. |
| 4 | + |
| 5 | +## Workflow |
| 6 | + |
| 7 | +1. **Plan first.** Ensure the task is well-defined before writing code. If unclear, work with the user to flesh out details. No sloppy/spaghetti code — every feature/fix must be clearly understood first. |
| 8 | +2. **Bugfixes:** write a regression test that fails before writing the fix. |
| 9 | +3. **After implementation:** act as an adversarial reviewer. Scrutinize the diff against all rules in this file. Call out numbered issues, then wait for the user to request followup changes. |
| 10 | + |
| 11 | +## Commands |
| 12 | + |
| 13 | +Use `uv` for everything — never bare `python` or `python3`. |
| 14 | + |
| 15 | +``` |
| 16 | +uv sync # install deps |
| 17 | +uv run pytest tests/units --cov --no-cov-on-fail --cov-report= # unit tests (>=72% coverage) |
| 18 | +uv run pytest tests/integration # integration tests (slow) |
| 19 | +uv run ruff check . # lint |
| 20 | +uv run ruff format . # format |
| 21 | +uv run pyright reflex tests # type check |
| 22 | +uv run python scripts/make_pyi.py # regenerate .pyi stubs |
| 23 | +uv run pre-commit run --all-files # all pre-commit hooks |
| 24 | +``` |
| 25 | + |
| 26 | +## Layout |
| 27 | + |
| 28 | +``` |
| 29 | +reflex/ # main framework package (app, state, compiler, components, utils, istate) |
| 30 | +packages/ # workspace sub-packages (reflex-base, reflex-components-*, reflex-docgen, reflex-ui) |
| 31 | +tests/units/ # unit tests, mirrors source tree |
| 32 | +tests/integration/ # Selenium integration tests (run in dev+prod modes) |
| 33 | + tests_playwright/ # Playwright integration tests (preferred for new tests) |
| 34 | +tests/benchmarks/ # performance benchmarks |
| 35 | +docs/ # documentation site (separate workspace member) |
| 36 | +``` |
| 37 | + |
| 38 | +## Code style |
| 39 | + |
| 40 | +- Concise, robust code. Reflex is a framework used in many ways — handle edge cases without unnecessary complexity. |
| 41 | +- Performance matters. Avoid suboptimal patterns (e.g. iterating a dict to find a value by identity). Suggest restructuring data/APIs if an operation can't be done efficiently. |
| 42 | +- Don't add expensive workarounds (e.g. `isinstance` checks) to paper over type-level problems — fix the root cause instead. |
| 43 | +- Don't repeat validation or be over-defensive; trust data that was already validated upstream. |
| 44 | +- Think in CPU cycles: avoid unnecessary data copies, redundant allocations, and gratuitous indirection. |
| 45 | +- Extract duplicated code into parameterized helpers. |
| 46 | +- No block comments (`# --- Section ---`, `# ============`). Plain inline comments only. |
| 47 | +- Be cautious creating new public APIs — they must be documented and supported long-term. |
| 48 | +- Google-style docstrings on all functions: one-line summary, optional detail sentence(s), then Args/Returns (or Yields)/Raises. |
| 49 | + |
| 50 | +## Testing |
| 51 | + |
| 52 | +- Write comprehensive tests for new/changed features; extend existing test files where possible. |
| 53 | +- Test functions at module level, not wrapped in classes. |
| 54 | +- **Unit tests:** `tests/units/`, run with `uv run pytest tests/units`. |
| 55 | + - unit tests should primarily cover a single module, and should be named accordingly, including subdirectories (e.g. `tests/units/istate/test_manager.py` for `reflex/istate/manager.py`). For subpackages, also include the corresponding path below `src/` (e.g. `tests/units/reflex_base/event/test_context.py` for `packages/reflex-base/src/reflex_base/event/context.py`). |
| 56 | +- **Integration tests:** prefer Playwright (`tests/integration/tests_playwright/`). Integration tests are slow — extend existing test apps rather than creating new ones for trivial functionality. Multiple test cases sharing one app is fine. |
| 57 | + |
| 58 | +### Integration test patterns |
| 59 | + |
| 60 | +Apps as factory functions, run via `AppHarness`: |
| 61 | + |
| 62 | +```python |
| 63 | +def SomeApp(): |
| 64 | + import reflex as rx |
| 65 | + class State(rx.State): |
| 66 | + value: str = "" |
| 67 | + def index(): |
| 68 | + return rx.box(rx.text(State.value)) |
| 69 | + app = rx.App() |
| 70 | + app.add_page(index) |
| 71 | + |
| 72 | +@pytest.fixture(scope="module") |
| 73 | +def some_app(tmp_path_factory) -> Generator[AppHarness, None, None]: |
| 74 | + with AppHarness.create(root=tmp_path_factory.mktemp("some_app"), app_source=SomeApp) as harness: |
| 75 | + yield harness |
| 76 | +``` |
| 77 | + |
| 78 | +Playwright tests use the `page` fixture and navigate to `harness.frontend_url`. Utilities in `tests/integration/utils.py` (polling, event ordering, storage). |
| 79 | + |
| 80 | +## .pyi stubs |
| 81 | + |
| 82 | +When adding/modifying components: `uv run python scripts/make_pyi.py`. Commit `pyi_hashes.json` (not `.pyi` files). If the diff removes many modules, run `uv sync`, delete `.pyi_generator_last_run`, and regenerate. |
| 83 | + |
| 84 | +## Breaking changes and deprecation |
| 85 | + |
| 86 | +Reflex has downstream users — don't break them. Provide a fallback path during deprecation. |
| 87 | + |
| 88 | +**Runtime warning** via `console.deprecate()`: |
| 89 | +```python |
| 90 | +from reflex_base.utils import console |
| 91 | +console.deprecate( |
| 92 | + feature_name="OldFeature", |
| 93 | + reason="Use NewFeature instead.", |
| 94 | + deprecation_version="<next dot version of latest git tag>", |
| 95 | + removal_version="1.0", |
| 96 | +) |
| 97 | +``` |
| 98 | +Set `deprecation_version` to the next dot version of the latest tag (`git fetch --tags` if needed, e.g. tag `v0.7.3` -> `"0.7.4"`). Set `removal_version` to next major unless directed otherwise. |
| 99 | + |
| 100 | +**Type-level deprecation** for deprecated methods/overloads using `typing_extensions.deprecated`, always inside a `TYPE_CHECKING` guard to avoid double warnings: |
| 101 | +```python |
| 102 | +from __future__ import annotations |
| 103 | +from typing import TYPE_CHECKING |
| 104 | +if TYPE_CHECKING: |
| 105 | + from typing_extensions import deprecated |
| 106 | + @deprecated("Use new_method() instead") |
| 107 | + def old_method(self) -> str: ... |
| 108 | +``` |
| 109 | + |
| 110 | +## Checklist |
| 111 | + |
| 112 | +Before submitting: |
| 113 | +1. Tests pass with adequate coverage |
| 114 | +2. `uv run ruff check .` and `uv run ruff format .` clean |
| 115 | +3. `uv run pyright reflex tests` passes |
| 116 | +4. `pyi_hashes.json` updated if components changed |
| 117 | +5. Documentation updated if user-facing behavior changed |
| 118 | +6. Deprecation warnings added if breaking changes introduced |
0 commit comments