From 9f89e0b015f5e0aff8d8fa018d810158d3f06256 Mon Sep 17 00:00:00 2001 From: amsraman Date: Fri, 5 Jun 2026 14:36:35 -0700 Subject: [PATCH] change source --- docs/ai_builder/integrations/agents_md.md | 10 ++++- docs/getting_started/installation.md | 33 +++++++++++++++ .../src/reflex_base/constants/__init__.py | 2 + .../src/reflex_base/constants/config.py | 11 +++++ reflex/reflex.py | 13 +++++- reflex/utils/frontend_skeleton.py | 33 ++++++++++++++- tests/units/utils/test_utils.py | 40 +++++++++++++++++++ 7 files changed, 139 insertions(+), 3 deletions(-) diff --git a/docs/ai_builder/integrations/agents_md.md b/docs/ai_builder/integrations/agents_md.md index 4a6b8291623..c50af4b376f 100644 --- a/docs/ai_builder/integrations/agents_md.md +++ b/docs/ai_builder/integrations/agents_md.md @@ -17,7 +17,15 @@ The [reflex-dev/agent-skills](https://github.com/reflex-dev/agent-skills) reposi ## Installation -Download the template into your project root, next to `rxconfig.py`: +The fastest way is to scaffold it as part of a new app. Pass `--agents` to `reflex init` and Reflex writes a starter `AGENTS.md` into the project root alongside `rxconfig.py`: + +```bash +reflex init --agents +``` + +An existing `AGENTS.md` is never overwritten, so it is safe to re-run. + +To add the template to an existing project, download it into the project root, next to `rxconfig.py`: ```bash curl -fsSL https://raw.githubusercontent.com/reflex-dev/agent-skills/main/AGENTS.md -o AGENTS.md diff --git a/docs/getting_started/installation.md b/docs/getting_started/installation.md index d0155e28968..d0fea6f2016 100644 --- a/docs/getting_started/installation.md +++ b/docs/getting_started/installation.md @@ -2,6 +2,39 @@ ~3 minutes · Requires Python 3.10+. +```md alert info +# Reading this as an AI agent or coding assistant? + +You're likely here to build a Reflex app for someone. Reflex does **not** behave like the Flask/FastAPI/React code in your training data — read this before writing any code. + +**Get the current docs (don't rely on training data — the API changes between versions):** + +- Fetch [`https://reflex.dev/llms.txt`](https://reflex.dev/llms.txt) for a token-efficient map of the docs and core concepts. +- Use the [Reflex MCP server](/docs/ai-builder/integrations/mcp-overview) (`https://build.reflex.dev/mcp`) for live component/prop lookup so you don't hallucinate APIs. *(MCP access is an enterprise feature.)* +- Run `uv run reflex --version` and trust the live docs for that version over memory. + +**Drop a rules file in the project root** (`AGENTS.md`, or `CLAUDE.md`/`.cursorrules` for your tool) so these conventions persist across your session — a starter is below. +``` + +Starter rules file: + +```text +# Reflex conventions + +- Reflex is pure Python that compiles to a React frontend. Do NOT write JS, HTML, or JSX. +- Components are function calls that return components; pass props as keyword args. +- NEVER use plain Python control flow on state Vars inside the render tree. + No `if`, `for`, `len()`, or f-strings over a Var — use `rx.cond`, `rx.foreach`, + and Var operators instead. (This is the most common mistake.) +- State lives in `rx.State` subclasses. State only mutates inside event-handler + methods — never at module load or render time. Derived values use `@rx.var`. +- Event handlers may be `async` and may `yield` to push intermediate UI updates. +- Always run commands with `uv run` (e.g. `uv run reflex run`). Never bare `python`. +- `.web/` is generated output — never edit or commit it. `rxconfig.py` is the config entry point. +- Verify your work headlessly: `CI=1 uv run reflex run` (frontend :3000, backend :8000), + add `--loglevel debug` to diagnose failures. +``` + ## Virtual Environment We recommend [uv](https://docs.astral.sh/uv/) as the default; [venv](https://docs.python.org/3/library/venv.html), [conda](https://conda.io/), and [poetry](https://python-poetry.org/) are alternatives. diff --git a/packages/reflex-base/src/reflex_base/constants/__init__.py b/packages/reflex-base/src/reflex_base/constants/__init__.py index 1d9480761a4..e442355d9a2 100644 --- a/packages/reflex-base/src/reflex_base/constants/__init__.py +++ b/packages/reflex-base/src/reflex_base/constants/__init__.py @@ -39,6 +39,7 @@ ) from .config import ( ALEMBIC_CONFIG, + AgentsMd, Config, DefaultPorts, Expiration, @@ -82,6 +83,7 @@ "ROUTE_NOT_FOUND", "SESSION_STORAGE", "SETTER_PREFIX", + "AgentsMd", "Bun", "ColorMode", "CompileContext", diff --git a/packages/reflex-base/src/reflex_base/constants/config.py b/packages/reflex-base/src/reflex_base/constants/config.py index e1e8a4c6d74..104bb05920a 100644 --- a/packages/reflex-base/src/reflex_base/constants/config.py +++ b/packages/reflex-base/src/reflex_base/constants/config.py @@ -49,6 +49,17 @@ class GitIgnore(SimpleNamespace): } +class AgentsMd(SimpleNamespace): + """AGENTS.md constants.""" + + # The AGENTS.md file written to the app root. + FILE = Path("AGENTS.md") + # The canonical AGENTS.md maintained in the reflex-dev/agent-skills repo. + CANONICAL_URL = ( + "https://raw.githubusercontent.com/reflex-dev/agent-skills/main/AGENTS.md" + ) + + class PyprojectToml(SimpleNamespace): """Pyproject.toml constants.""" diff --git a/reflex/reflex.py b/reflex/reflex.py index bcfec77dd77..ba1c5933ae2 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -58,6 +58,7 @@ def _init( name: str, template: str | None = None, ai: bool = False, + agents: bool = False, ): """Initialize a new Reflex app in the given directory.""" from reflex.utils import exec, frontend_skeleton, prerequisites, templates @@ -89,6 +90,10 @@ def _init( # Initialize the .gitignore. frontend_skeleton.initialize_gitignore() + # Optionally write a sample AGENTS.md for AI coding agents. + if agents: + frontend_skeleton.initialize_agents_md() + template_msg = f" using the {template} template" if template else "" if Path(constants.PyprojectToml.FILE).exists(): needs_user_manual_update = False @@ -122,13 +127,19 @@ def _init( is_flag=True, help="Use AI to create the initial template. Cannot be used with existing app or `--template` option.", ) +@click.option( + "--agents", + is_flag=True, + help="Write a sample AGENTS.md to guide AI coding agents working in the app.", +) def init( name: str, template: str | None, ai: bool, + agents: bool, ): """Initialize a new Reflex app in the current directory.""" - _init(name, template, ai) + _init(name, template, ai, agents) def _compile_app(*, avoid_dirty_check: bool = True): diff --git a/reflex/utils/frontend_skeleton.py b/reflex/utils/frontend_skeleton.py index 6212fb43121..01d970ec35a 100644 --- a/reflex/utils/frontend_skeleton.py +++ b/reflex/utils/frontend_skeleton.py @@ -11,7 +11,7 @@ from reflex.compiler import templates from reflex.compiler.utils import write_file -from reflex.utils import console, path_ops +from reflex.utils import console, net, path_ops from reflex.utils.prerequisites import get_project_hash, get_web_dir from reflex.utils.registry import get_npm_registry @@ -43,6 +43,37 @@ def initialize_gitignore( gitignore_file.write_text("\n".join(files_to_ignore) + "\n") +def initialize_agents_md( + agents_file: Path = constants.AgentsMd.FILE, + url: str = constants.AgentsMd.CANONICAL_URL, +): + """Write the AGENTS.md for AI coding agents, fetched from the canonical repo. + + Does not overwrite an existing file so a user's customizations are preserved. + Aborts if the canonical file cannot be fetched. + + Args: + agents_file: The AGENTS.md file to create in the app root. + url: The canonical AGENTS.md to download. + """ + if agents_file.exists(): + console.debug(f"{agents_file} already exists, skipping.") + return + + import httpx + + console.debug(f"Fetching {url}") + try: + response = net.get(url, timeout=5) + response.raise_for_status() + except httpx.HTTPError as e: + console.error(f"Failed to fetch AGENTS.md from {url} due to {e}.") + raise SystemExit(1) from None + + console.debug(f"Creating {agents_file}") + agents_file.write_text(response.text) + + def _read_dependency_file(file_path: Path) -> tuple[str | None, str | None]: """Read a dependency file with a forgiving encoding strategy. diff --git a/tests/units/utils/test_utils.py b/tests/units/utils/test_utils.py index ffc3c975780..94b1b45ee4e 100644 --- a/tests/units/utils/test_utils.py +++ b/tests/units/utils/test_utils.py @@ -421,6 +421,46 @@ def test_initialize_non_existent_gitignore( assert set(file_content) - expected == set() +def test_initialize_agents_md_fetches_canonical(tmp_path, mocker): + """Test that AGENTS.md is fetched from the canonical repo when absent.""" + agents_file = tmp_path / "AGENTS.md" + response = mocker.Mock() + response.text = "# canonical agents" + get = mocker.patch("reflex.utils.net.get", return_value=response) + + frontend_skeleton.initialize_agents_md( + agents_file=agents_file, url="http://x/AGENTS.md" + ) + + get.assert_called_once_with("http://x/AGENTS.md", timeout=5) + assert agents_file.read_text() == "# canonical agents" + + +def test_initialize_agents_md_preserves_existing(tmp_path, mocker): + """Test that an existing AGENTS.md is never overwritten or re-fetched.""" + agents_file = tmp_path / "AGENTS.md" + agents_file.write_text("custom content") + get = mocker.patch("reflex.utils.net.get") + + frontend_skeleton.initialize_agents_md(agents_file=agents_file) + + assert agents_file.read_text() == "custom content" + get.assert_not_called() + + +def test_initialize_agents_md_aborts_on_fetch_failure(tmp_path, mocker): + """Test that a failed fetch aborts init without leaving a partial file.""" + import httpx + + agents_file = tmp_path / "AGENTS.md" + mocker.patch("reflex.utils.net.get", side_effect=httpx.ConnectError("boom")) + + with pytest.raises(SystemExit): + frontend_skeleton.initialize_agents_md(agents_file=agents_file) + + assert not agents_file.exists() + + def test_initialize_requirements_txt_skips_when_pyproject_exists(tmp_path): """Test that pyproject-based apps do not get a requirements.txt file.""" pyproject_file = tmp_path / "pyproject.toml"