{"owner":"reflex-dev","repo":"reflex","hasSkills":true,"totalSkillsCount":63,"totalTokensCount":75596,"categories":["anthropic-skill","root-instruction","claude-rule","plugin-manifest"],"hasMcp":false,"mcpConfig":null,"found":[".claude/skills/prerelease-test/SKILL.md",".claude/skills/prerelease-test/references/agent-brief.md",".claude/skills/prerelease-test/references/clusters.md",".claude/skills/prerelease-test/references/orchestration.md",".claude/skills/prerelease-test/references/reporting.md","AGENTS.md","CLAUDE.md","packages/hatch-reflex-pyi/README.md","packages/integrations-docs/README.md","packages/integrations-docs/src/integrations_docs/docs/airtable.md","packages/integrations-docs/src/integrations_docs/docs/anthropic.md","packages/integrations-docs/src/integrations_docs/docs/aws.md","packages/integrations-docs/src/integrations_docs/docs/azure_auth.md","packages/integrations-docs/src/integrations_docs/docs/cartesia.md","packages/integrations-docs/src/integrations_docs/docs/cohere.md","packages/integrations-docs/src/integrations_docs/docs/database.md","packages/integrations-docs/src/integrations_docs/docs/databricks.md","packages/integrations-docs/src/integrations_docs/docs/descope.md","packages/integrations-docs/src/integrations_docs/docs/gemini.md","packages/integrations-docs/src/integrations_docs/docs/github.md","packages/integrations-docs/src/integrations_docs/docs/google_auth.md","packages/integrations-docs/src/integrations_docs/docs/groq.md","packages/integrations-docs/src/integrations_docs/docs/hubspot.md","packages/integrations-docs/src/integrations_docs/docs/hugging_face.md","packages/integrations-docs/src/integrations_docs/docs/langchain.md","packages/integrations-docs/src/integrations_docs/docs/linear.md","packages/integrations-docs/src/integrations_docs/docs/notion.md","packages/integrations-docs/src/integrations_docs/docs/okta_auth.md","packages/integrations-docs/src/integrations_docs/docs/openai.md","packages/integrations-docs/src/integrations_docs/docs/overview.md","packages/integrations-docs/src/integrations_docs/docs/perplexity.md","packages/integrations-docs/src/integrations_docs/docs/replicate.md","packages/integrations-docs/src/integrations_docs/docs/resend.md","packages/integrations-docs/src/integrations_docs/docs/roboflow.md","packages/integrations-docs/src/integrations_docs/docs/snowflake.md","packages/integrations-docs/src/integrations_docs/docs/stripe.md","packages/integrations-docs/src/integrations_docs/docs/supabase.md","packages/integrations-docs/src/integrations_docs/docs/twilio.md","packages/reflex-base/README.md","packages/reflex-bench/README.md","packages/reflex-build-sdk/README.md","packages/reflex-build-sdk/openapi.json","packages/reflex-components-code/README.md","packages/reflex-components-core/README.md","packages/reflex-components-dataeditor/README.md","packages/reflex-components-gridjs/README.md","packages/reflex-components-internal/README.md","packages/reflex-components-lucide/README.md","packages/reflex-components-markdown/README.md","packages/reflex-components-moment/README.md","packages/reflex-components-plotly/README.md","packages/reflex-components-radix/README.md","packages/reflex-components-react-player/README.md","packages/reflex-components-recharts/README.md","packages/reflex-components-sonner/README.md","packages/reflex-docgen/README.md","packages/reflex-hosting-cli/README.md","packages/reflex-otel/README.md","packages/reflex-release/README.md","packages/reflex-site-shared/README.md","packages/reflex-workflow/README.md","packages/reflex-workflow/benchmarks/README.md","packages/reflex-workflow/examples/README.md"],"skills":{".claude/skills/prerelease-test/SKILL.md":"---\nname: prerelease-test\ndescription: Run the independent pre-release QA campaign for a Reflex release train. Discovers what shipped by reading every CHANGELOG.md on the pre-release branch, checks each package actually published to PyPI, then exercises the new features end-to-end in real apps driven by a real browser using ONLY published packages, upgrade-tests reflex-examples apps from the previous stable, regression-tests reflex-enterprise demos, audits wheel/sdist packaging, and produces a triaged FINDINGS.md plus a fix-before-release plan. Use this whenever a Reflex release is being prepared or checked — the user mentions a pre-release, an alpha/beta/rc, an `r/pre-*` branch, \"about to release\", release QA, validating a release candidate, or re-verifying that release-blocking fixes landed in a newer alpha. Also use it for the narrower slices on their own: smoke-testing published packages, upgrade/regression testing example apps against a new version, or auditing that packages ship their `.pyi` stubs in both wheel and sdist.\n---\n\n# Reflex pre-release testing\n\nThis skill runs the QA campaign that stands between a pre-release and a release: independent,\nadversarial, end-to-end exercise of what actually got published, from the perspective of a user\nwho runs `pip install reflex` and opens a browser.\n\nIts value comes from three habits, not from breadth of assertions:\n\n1. **Only published packages.** Everything installs from PyPI into throwaway venvs. The checkout\n   has unreleased code, different metadata, and a different dependency graph — testing it tells\n   you nothing about what users will get, and a package that failed to publish is itself a\n   release blocker you would otherwise miss.\n2. **Baseline against the previous stable.** A defect that also reproduces on the last release is\n   a bug; one that only reproduces on the new version is a regression and usually a blocker.\n   Without the baseline run you cannot tell them apart, and the triage that follows is guesswork.\n3. **Adversarially verify before reporting.** Have a second agent reproduce each claimed issue\n   from the written repro alone and actively try to refute it. In practice this refutes or\n   reclassifies a meaningful share of findings — and it is what makes the report trustworthy\n   enough for maintainers to act on directly.\n\n## Deliverables\n\nProduce these under `prerelease-testing/<date>-<version>/` in the repo and commit them to a work\nbranch as you go (never to `main`):\n\n- `FINDINGS.md` — executive summary, numbered findings with repro + evidence + regression status,\n  refuted claims, and per-cluster summaries. Templates: `references/reporting.md`.\n- `RELEASE_PLAN.md` — triage into fix-before-release vs file-as-issue. Rubric below.\n- One directory per test cluster containing the sample app sources (no `.web/`, `node_modules/`,\n  venvs), the driver scripts, `NOTES.md` with exact rerun commands, logs and screenshots.\n- `README.md` — what each cluster covers and how to reuse it for the next release.\n\nFindings must be reproducible by a stranger from `NOTES.md` alone. That is the bar: a fix agent\ngets handed the finding and nothing else.\n\n## Phases\n\nWork these in order. Phases 2–5 can overlap; 0 and 1 gate everything.\n\n### Phase 0 — Scope discovery\n\nFind the pre-release branch (`git ls-remote --heads origin 'r/pre-*'`, or the user names it), then\nread **every** `CHANGELOG.md` on it: the root one plus `packages/*/CHANGELOG.md`. The top entry of\neach is what this train ships.\n\nRun the discovery script to extract every package's version and confirm each is published:\n\n    uv run --script .claude/skills/prerelease-test/scripts/check_release_versions.py --ref <git-ref>\n\n(Script paths in this skill are repo-root-relative — the repo has its own unrelated `scripts/`\ndirectory, so the prefix matters.) It exits 1 when a package is confirmed missing and 2 when a\ncheck could not complete, so a proxy hiccup never reads as a missing package. An unpublished\nversion is a finding in its own right — report it immediately rather than working around it.\n\nRead the linked PRs for anything whose intent is not obvious from the changelog line; the GitHub\nMCP tools (`mcp__github__pull_request_read`) do this well. Understanding what a change was *for*\nis what lets you test it as a user rather than as a checklist.\n\n### Phase 1 — De-risk with a smoke test\n\nBefore any fan-out: one venv, `reflex init --template blank`, `reflex run`, then drive it in\nChromium with `.claude/skills/prerelease-test/scripts/drive_app.py`. This shakes out environment\nproblems (proxy, bun installs, browser path) once, in a context where you can debug them, instead\nof inside ten parallel agents.\n\nThe scripts carry PEP 723 metadata, so `uv run --script <path>` runs each one in its own isolated\nenvironment (the driver pulls in playwright that way); running them with an existing driver venv's\ninterpreter works too.\n\nAlso confirm the dependency graph resolves the way the changelog says it should (e.g. optional\ndependencies genuinely absent, sub-packages pinned as intended).\n\n### Phase 2 — Feature exploration fan-out\n\nDecompose the changelog into clusters of related changes and give each to its own agent, with an\nadversarial verification stage behind it. See `references/clusters.md` for how to cut the clusters\nand a standing coverage list; `references/orchestration.md` for the Workflow script, schemas and\nport map.\n\nThe instruction that makes this productive: **real-world exploration, not coverage filling.**\nCombine each new feature with the things users actually combine it with — State vars,\n`rx._x.client_state`, `rx.ComponentState`, `@rx.memo` wrapping, `rx.foreach`/`rx.cond`, event\nchains, background tasks, multiple pages and navigation, dev *and* prod mode. Bugs live in the\ninteractions, and the original PR's tests already cover the happy path.\n\nEvery run inspects all four channels: server log, browser console (errors *and* warnings), network\ntab (failed requests, 4xx/5xx), and the rendered page. Findings frequently show up in a channel\nnobody asserted on.\n\n### Phase 3 — Upgrade regression\n\nUsers upgrade in place; that path has its own failure modes (lockfile migration, pruned packages,\nstale `.web/`). Clone `reflex-dev/reflex-examples`, pick apps that span the feature surface —\nincluding ones using third-party packages (`reflex-local-auth`, `reflex-global-hotkey`) and\n`reflex[db]`/API apps — then for each:\n\n1. Install the **previous stable** (no `--prerelease` flag, so requirements resolve as a user's\n   would), run it, and drive its real user flows in the browser. This is your baseline.\n2. Upgrade the *same* venv and *same* app directory in place to the new version, preserving\n   `.web/` and `reflex.lock/`. Watch the first run's log closely — that is where migration\n   happens. Re-drive the identical flows and compare.\n3. Do one cold run (`rm -rf .web`) to check the fresh-install path converges to the same state.\n\nDiff `.web/package.json` before and after; unexpected dependency changes are findings.\n\n### Phase 4 — Enterprise regression\n\nDownstream breakage is the most common release blocker, because removing a public name is\ninvisible until something imports it. Install the **published** `reflex-enterprise` (never the\ncheckout) against the new reflex and run its demos — ag-grid, map, dnd, mantine, flow, the MCP\nplugin, OIDC. Baseline against the previous stable whenever something fails, so you can say\nwhether the new release broke it.\n\nBefore running anything, grep the published enterprise wheel for names the changelog says moved or\nwere removed; that finds the breakage in seconds instead of hours.\n\n### Phase 5 — Packaging audit\n\nAudit every package in the train; the discovery script feeds it the whole list. Chain the two with\n`&&`, never a pipe — a pipe reports only the audit's exit status, so a package whose PyPI check\nnever completed would be dropped from the list and the audit would still print PASS over what was\nleft. The `&&` is what makes that impossible: the audit runs only when discovery exits 0.\n\n    uv run --script .claude/skills/prerelease-test/scripts/check_release_versions.py \\\n      --ref <ref> --specs > specs.txt \\\n      && xargs uv run --script .claude/skills/prerelease-test/scripts/audit_pyi.py \\\n        --manifest-ref <ref> < specs.txt\n\nIt verifies each package ships its own generated `.pyi` stubs in **both** wheel and sdist, that\nthey are byte-identical between the two, that no package leaks another package's stubs, and that\ncounts line up with `pyi_hashes.json` (a package absent from the manifest must ship none).\n\nStub content hashes legitimately differ from the committed manifest because the build hook\nregenerates them at release time — compare *presence and counts*, and wheel against sdist.\n\n### Phase 6 — Triage and report\n\nWrite `FINDINGS.md` first (everything confirmed), then `RELEASE_PLAN.md` splitting findings into:\n\n**Fix before release** — anything meeting one of:\n- a confirmed regression against the previous stable,\n- security-relevant (path traversal, unauthenticated input handling, injection),\n- significant user impact, or trivially small to fix (a one-line guard, a missing default).\n\n**File as issues, fix after** — everything else, including pre-existing defects the campaign\nhappened to surface. Downstream (enterprise) issues go to that project's tracker, not this repo's.\n\nAlso flag decisions only a maintainer can make — an undocumented behavior change is either a bug\nor a missing changelog entry, and which one it is is their call. Ask rather than assume.\n\n### Phase 7 — Re-verify the next build\n\nWhen a new alpha ships with the fixes, re-run the *original failing repro* for each finding\n(not just the unit tests) against the new published packages, plus a general smoke. Append the\npass/fail table to `FINDINGS.md`. When the final ships, do one last stock-install smoke:\n`pip install reflex==<final>` with no prerelease flag, init, run, browser, and confirm the\nresolved graph is all-final.\n\n## Working rules\n\n- **Isolation.** Every agent gets its own venv and its own reserved port range; never install into\n  a shared venv. See the port map in `references/orchestration.md`.\n- **The traps are real.** `references/agent-brief.md` is the brief to hand every agent — it carries\n  the environment gotchas (checkout shadowing, proxy variables breaking installs) and the list of\n  known-benign console noise. Agents that skip it rediscover the same problems and report noise as\n  findings.\n- **Concurrency.** Dev servers are heavy (bun + vite + granian). On a 4-CPU box run about two\n  agents at a time and one dev server per agent; more just makes everything slow and flaky.\n- **Commit as you go.** Each cluster's artifacts land on the work branch when that cluster\n  finishes, so a long campaign is never one unrecoverable batch.\n- **Never fix framework code during the campaign.** Testing and fixing are separate engagements\n  with separate review standards; mixing them costs you the independence that makes the findings\n  credible. Record the repro and move on. (If the user then asks for fixes, that is a new task —\n  one PR per finding, regression test first, `references/reporting.md` has the PR conventions.)\n\n## Scaling the campaign\n\nFull campaign is roughly 30 agents over several hours. Scale down by dropping whole phases rather\nthan by testing each phase more shallowly — a shallow pass produces false confidence:\n\n- **Quick check** (~30 min): phases 0, 1, 5, plus grep-based downstream checks from phase 4.\n- **Standard** (~2 h): add phase 2 over the three or four highest-risk clusters.\n- **Full**: everything, with adversarial verification on every claimed issue.\n\nAsk the user which they want if the request is ambiguous and the difference matters.\n",".claude/skills/prerelease-test/references/agent-brief.md":"# The agent brief\n\nCopy this into the campaign scratchpad (e.g. `$SB/AGENT_BRIEF.md`), fill the `<...>` placeholders,\nand tell every test agent to read it first. It carries the rules that keep results trustworthy and\nthe environment traps that otherwise get rediscovered — expensively — by each agent in turn.\n\nKeep it in a file rather than pasting it into each prompt: agents re-read it when they get\nconfused, and updating one file updates the whole fleet.\n\n---\n\n## BRIEF TEMPLATE (copy from here)\n\nYou are one of several agents independently exercising the reflex `<VERSION>` pre-release\n(published `<DATE>`) as a real-world user of the framework. Your job: build small sample apps and\nrepro scripts for your assigned feature cluster, run them END-TO-END (real server, real Chromium),\nand hunt for anomalies. You REPORT issues; you never fix framework code.\n\n### HARD RULES\n\n1. **NEVER install reflex (or any workspace package) from the local checkout at `<REPO>`.** No\n   `uv sync`, no `uv run`, no `pip install -e`, no `uv pip install .` anywhere under it.\n   Everything installs from PyPI. We are testing what users receive, not what the tree contains.\n2. **Never run python with the checkout as your working directory.** `<REPO>/reflex/` shadows the\n   installed package, so `import reflex` silently picks up unreleased source and your results\n   become fiction. Run scripts from a neutral directory and start each repro with an assertion\n   naming the venv whose python is running it — the shared one below, or your own:\n   ```python\n   import reflex\n\n   assert \"<VENV_PATH>\" in reflex.__file__, reflex.__file__\n   ```\n   A guard that names some other venv fails on every run and gets deleted, which leaves you with\n   no guard at all.\n3. Reading the checkout is fine and encouraged — release source is on branch `<PRERELEASE_BRANCH>`.\n   For PR context load the GitHub MCP tools via ToolSearch (`select:mcp__github__pull_request_read`).\n4. Do NOT run any `git` write commands (add/commit/checkout/...) in the checkout. The orchestrator\n   commits artifacts.\n5. Do NOT fix bugs you find — record precise repro steps instead.\n6. Kill every server and browser you start before you finish (track PIDs; verify with `ps`). Other\n   agents share this machine — run at most ONE dev server at a time unless your cluster needs two.\n\n### Environment\n\n- Scratchpad root: `SB=<SCRATCHPAD>`\n- **Prebuilt shared venv (READ-ONLY — never install into it):** `$SB/envs/<SHARED_VENV>` has\n  `reflex==<VERSION>` and the alpha sub-packages. Use `$SB/envs/<SHARED_VENV>/bin/reflex` directly.\n- Need other deps or versions? Make your OWN venv:\n  ```\n  uv venv $SB/envs/<yours> --python 3.11\n  uv pip install --python $SB/envs/<yours>/bin/python --prerelease=allow 'reflex==<VERSION>' <extras>\n  ```\n  Always pass `--prerelease=allow` for alphas; PyPI is the default index — never point it at the\n  checkout. Python 3.12/3.13/3.14 are available via `uv venv --python 3.14` etc.\n- **Playwright driver venv:** `$SB/envs/driver/bin/python` (playwright, httpx, websockets).\n  Chromium: `/opt/pw-browsers/chromium` — launch with\n  `p.chromium.launch(executable_path=\"/opt/pw-browsers/chromium\")`.\n  A ready-made driver with console/network capture is at\n  `.claude/skills/prerelease-test/scripts/drive_app.py` in the checkout (read-only use is fine).\n- **Local HTTP needs proxy bypass on the CLIENT side only:** prefix curl/Playwright commands with\n  `NO_PROXY=localhost,127.0.0.1 no_proxy=localhost,127.0.0.1` (curl: `--noproxy '*'`).\n  Do NOT export those variables into the reflex server's environment — it breaks bun's package\n  installs through the proxy, which looks like a framework bug and is not.\n- Set `REFLEX_TELEMETRY_ENABLED=false` for every reflex command.\n- Node and bun are preinstalled. Enterprise apps need `CI=true` to bypass the dev login gate.\n- App working dirs: `$SB/apps/<cluster>/...`. Run servers on YOUR ASSIGNED PORTS:\n  `reflex run --frontend-port <FP> --backend-port <BP>`. The first run does a bun install (1–2 min);\n  poll the frontend URL until it returns 200 for up to ~6 minutes before concluding failure.\n- `--loglevel debug` gives verbose server logs; redirect to a file and actually read it.\n\n### What \"testing\" means here\n\n- Real-world exploration, not coverage filling. Combine the feature with State vars,\n  `rx._x.client_state`, `@rx.memo` wrapping, `rx.ComponentState`, `rx.foreach`/`rx.cond`, event\n  chains (`yield Other.handler()`), background tasks, multiple pages and navigation — whatever\n  plausibly interacts. The original PR already tested the happy path.\n- Drive the app in Chromium as a user would: click, type, navigate, upload, drag, use the keyboard.\n- On EVERY run capture and inspect: (a) the server log file, (b) browser console messages (errors\n  AND warnings), (c) failed requests / 4xx-5xx responses, (d) screenshots at key moments.\n- Baseline comparisons are what make findings actionable: if behavior looks wrong, check the\n  previous stable (`uv pip install 'reflex==<PREV_STABLE>'` in its own venv). Only-on-new is a\n  regression and high severity; both-versions is context worth noting, not a blocker.\n- Prod matters too: `reflex run --env prod` compiles and serves the built frontend. Test both modes\n  when your feature could differ (hydration, memoization, routing, prerender).\n\n### Known-benign noise — do not report these as findings\n\n- Browser console: the React Router \"💿 Hey developer\" HydrateFallback log, vite\n  `connecting.../connected` debug lines, the React DevTools download info line.\n- `reflex init` logging a few \"Failed to connect to https://registry.npmmirror.com\" lines before\n  falling back (this environment blocks that mirror). Do report it if the fallback itself fails.\n- Transient bun \"incorrect peer dependency\" warnings during a one-time upgrade migration, provided\n  the final lockfile is consistent.\n\nIf you see something surprising that is not on this list, investigate it — several real findings\nhave surfaced first as an unexplained warning.\n\n### Deliverables (mandatory)\n\n1. Copy reusable artifacts into the repo (plain `cp`/`rsync`, no git):\n   `DEST=<ARTIFACT_ROOT>/<cluster>/`\n   - the app source dirs, EXCLUDING `.web/`, `node_modules/`, `.states/`, `assets/external/`,\n     `*.db`, venvs\n   - your Playwright/repro scripts\n   - `NOTES.md`: what you tested, how to rerun it (exact commands), what you observed, including\n     benign quirks\n2. Return structured findings: every discrete check as a test entry (pass/fail/anomaly/skipped)\n   with enough repro detail that another agent can reproduce a failure from `NOTES.md` and your\n   scripts alone, without your conversation. An \"anomaly\" is anything surprising (console error,\n   warning, traceback, visual glitch, perf cliff) even when functionality works.\n\n### Timeboxing\n\nBe thorough but keep moving: if one sub-test resists debugging for ~10 minutes, record it as an\nanomaly with logs attached and continue. Finishing the whole cluster beats perfecting one test.\n",".claude/skills/prerelease-test/references/clusters.md":"# Cutting the changelog into clusters\n\nA cluster is one agent's assignment: a group of changelog entries that share a subsystem, so the\nagent can build one or two apps that exercise all of them together and notice how they interact.\n\n## How to cut them\n\nGroup by **where the change lives at runtime**, not by which PR shipped it. Entries that touch the\nsame subsystem belong together even when they came from unrelated PRs, because the interesting\nbugs are in their interaction — and one app can cover them all.\n\nAim for 8–12 clusters of 2–6 changelog entries each. A cluster that needs more than two apps is\ntoo big; one with a single trivial entry should be folded into a neighbour.\n\nEach cluster brief should carry:\n- the changelog lines verbatim (agents should not have to re-derive what shipped),\n- the PR numbers, so the agent can read intent,\n- concrete \"combine it with\" suggestions — this is what turns a checklist into exploration,\n- anything the entry implies but does not state (a perf claim to measure, a behavior that should\n  differ between dev and prod).\n\n## Standing coverage checklist\n\nMost Reflex releases touch some subset of these. Use it to check you have not left a shipped change\nunassigned, and as a source of interaction ideas.\n\n| Area | What to build | Interactions worth forcing |\n|---|---|---|\n| Routing / navigation | Multi-page app with dynamic (`[id]`), catchall (`[[...splat]]`) and static-sibling routes; slow `on_load` | Navigate away mid-`on_load`; two tabs on different dynamic values; browser back/forward; direct load vs client-side nav; prod mode |\n| State & event loop | Counter hammered by clicks while a background task writes | Background task + foreground handler racing; `yield`-streaming handlers; `async with self`; abrupt disconnect mid-stream |\n| Components / props | One page per changed component | Prop bound to a State var, to a `client_state` var, and inside `@rx.memo`; explicit `style=` merged with forwarded props |\n| Memoization | `@rx.memo` component with state-bound props and an event-handler prop, plus render counters | Memo in `rx.foreach`; memo wrapping `ComponentState`; two memos sharing a name in different modules; dev vs prod |\n| Typing / annotations | State vars using every annotation shape the entry mentions | Assign at runtime (not just compile); pass the handler *uncalled* to a trigger; run on the oldest and newest supported Python |\n| Uploads | `rx.upload` with buffered and streamed handlers | Hostile filenames (traversal, unicode, all-dots, spaces); raw multipart via httpx alongside browser uploads |\n| Logging / CLI | Run every CLI verb with and without the logging flags | Strict JSON-lines parsing of stdout; a user app that configures `logging` itself; missing optional sub-packages |\n| Config / plugins | App with the config knob set, unset, and set via env var | Deprecated form alongside the new form; plugin explicitly enabled vs implicit |\n| Build / prod / export | Multi-page app through `run --env prod`, `export`, `run --env preview` | Serve exported frontend statically with a backend-only server; inspect generated `.web/package.json`; custom component with a changed library |\n| Registration / multi-app | Two apps in one process; `AppHarness` twice | Sequential and simultaneous; check for registration leakage between them |\n| Optional dependencies | Bare install, each extra, and the upgrade path | Import the optional package's feature without the extra and judge the error message quality |\n| DevTools / perf | App with nested substates, custom components, client-only wrappers | Walk React fibers for `displayName`; record navigation main-thread cost; verify perf claims rather than trusting them |\n\n## Downstream and packaging clusters\n\nTwo clusters that are not feature-shaped but catch the highest-severity problems:\n\n- **Breaking-change surface.** For every entry under \"Breaking Changes\" (and every removal you spot\n  in the diff), ask what a downstream caller sees. Grep the published `reflex-enterprise` wheel and\n  the popular third-party packages (`reflex-local-auth`, `reflex-global-hotkey`) for the removed\n  names. A bare `AttributeError`/`ImportError` with no pointer to the replacement is a finding even\n  when the removal itself was intended.\n- **Packaging.** `.claude/skills/prerelease-test/scripts/audit_pyi.py`, plus a check that each package's declared dependency pins\n  match what the changelog says and that installing from the sdist works.\n",".claude/skills/prerelease-test/references/orchestration.md":"# Orchestrating the fleet\n\n## Choosing the mechanism\n\nInvoking this skill is itself the opt-in for the Workflow tool, so a full campaign should use it —\nthe explore→verify pipeline is deterministic control flow over many agents, exactly what Workflow\nis for. For a quick check or a single cluster, plain `Agent` calls are simpler and cheaper.\n\nUse one workflow per phase rather than one giant script. Phase results change what you want to ask\nnext (a cluster that finds a breaking change reshapes the enterprise phase), and you stay in the\nloop between phases.\n\n## The explore → verify pipeline\n\nThe shape that matters: each cluster's findings go straight into verification without waiting for\nthe other clusters. Use `pipeline`, not a barrier — a slow cluster should not hold up verification\nof a fast one.\n\n```js\nexport const meta = {\n  name: 'prerelease-explore',\n  description: 'Exercise <version> feature clusters end-to-end, then adversarially verify findings',\n  phases: [{ title: 'Explore' }, { title: 'Verify' }],\n}\n\nconst SB = '<scratchpad>'\nconst DEST = '<artifact root>'\n\nconst FINDINGS_SCHEMA = {\n  type: 'object',\n  required: ['cluster', 'summary', 'tests', 'issues', 'artifacts_dir'],\n  properties: {\n    cluster: { type: 'string' },\n    summary: { type: 'string' },\n    tests: {\n      type: 'array',\n      items: {\n        type: 'object',\n        required: ['name', 'status', 'details'],\n        properties: {\n          name: { type: 'string' },\n          status: { type: 'string', enum: ['pass', 'fail', 'anomaly', 'skipped'] },\n          details: { type: 'string' },\n          repro: { type: 'string' },\n        },\n      },\n    },\n    issues: {\n      type: 'array',\n      items: {\n        type: 'object',\n        required: ['title', 'severity', 'repro'],\n        properties: {\n          title: { type: 'string' },\n          severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low'] },\n          repro: { type: 'string' },\n          evidence: { type: 'string' },\n          regression: { type: 'boolean', description: 'true if the previous stable behaves correctly' },\n        },\n      },\n    },\n    artifacts_dir: { type: 'string' },\n  },\n}\n\nconst VERDICT_SCHEMA = {\n  type: 'object',\n  required: ['confirmed', 'notes'],\n  properties: {\n    confirmed: { type: 'boolean' },\n    notes: { type: 'string' },\n    root_cause_guess: { type: 'string' },\n  },\n}\n\nphase('Explore')\nconst results = await pipeline(\n  CLUSTERS,\n  (c, _item, i) => agent(brief(c, i), { label: `explore:${c.key}`, phase: 'Explore', schema: FINDINGS_SCHEMA }),\n  async (res, c, i) => {\n    if (!res) return { cluster: c.key, agent_died: true }\n    // Cap the fan-out per cluster. Issues past the cap are absent from verified_issues but\n    // still present in res.issues, which is how the report tells them from verified ones.\n    const issues = (res.issues || []).slice(0, 4)\n    if (!issues.length) return res\n    const verdicts = await parallel(\n      issues.map((iss, j) => () =>\n        agent(verifyBrief(c, iss, j), { label: `verify:${c.key}:${j}`, phase: 'Verify', schema: VERDICT_SCHEMA })\n          // A dead verifier resolves falsy. Give it its own marker: `verdict: null` would\n          // read as a verdict that cleared the issue, and dropping the entry would leave a\n          // hole indistinguishable from an issue the cap never sent to a verifier.\n          .then((v) => (v ? { issue: iss, verdict: v } : { issue: iss, verifier_died: true })),\n      ),\n    )\n    return { ...res, verified_issues: verdicts }\n  },\n)\n// Dead explorers stay in as `agent_died` markers rather than being filtered out: a cluster\n// that produced nothing is a hole in the campaign, and silently dropping it is how a hole\n// gets mistaken for a clean result. Same for `verifier_died` above. Every marker is work\n// the campaign did not do, so the report must account for each one rather than skip it.\nreturn results.filter(Boolean)\n```\n\nThe verifier's prompt is what makes this work. It must:\n- reproduce **from the written repro alone**, in its own working directory, not by reading the\n  reporter's conversation — that is simultaneously a test of the repro's quality,\n- be told to actively **refute**: is this an environment quirk, an API misuse, pre-existing on the\n  previous stable, or a genuine defect?\n- set `confirmed: true` only for a genuine defect a fix agent should act on,\n- append a `## VERIFICATION` section to the cluster's `NOTES.md` so the record travels with the\n  artifacts.\n\n## Port map\n\nGive every agent a disjoint range and tell it to always pass `--frontend-port/--backend-port`\nexplicitly. Never let anything use the defaults (3000/8000) — that is how two agents collide and\nproduce confusing, unreproducible results.\n\n| Stage | Frontend | Backend |\n|---|---|---|\n| Explore agent *i* | `3100 + 40i` … +19 | `8100 + 40i` … +19 |\n| Verify agent *i.j* | `3600 + 40i + 4j` … +3 | `8600 + 40i + 4j` … +3 |\n| Orchestrator smoke | 3050–3059 | 8050–8059 |\n\n## Prompt scaffolding for each agent\n\nEvery cluster prompt should open with the same preamble, then the cluster-specific brief:\n\n```\nFIRST read <SB>/AGENT_BRIEF.md and follow every rule in it (isolated PyPI-only installs — never\ninstall from the checkout; end-to-end browser testing; artifact + NOTES.md deliverables; kill your\nprocesses).\nYour cluster key: \"<key>\". Working dir: <SB>/apps/<key>/. Artifact destination: <DEST>/<key>/.\nYour RESERVED ports: frontend <FP_START>-<FP_END>, backend <BP_START>-<BP_END> — always pass them\nexplicitly, and never bind outside them.\n<cluster brief: changelog lines verbatim, PR numbers, combine-with suggestions>\nAlso in scope: anything adjacent you notice (log warnings, console anomalies, network errors,\nvisual glitches). Record benign-but-surprising observations in NOTES.md and as 'anomaly' entries.\n```\n\nFill the port ends from the table above, not from a fixed span: an explore agent's range is 20\nports wide and a verify agent's is 4. A verifier told it owns 20 would reach into the next\nverifier's range, which is the collision the map exists to prevent.\n\n## Running it\n\n- Two agents at a time is right for a 4-CPU box; the workflow's own concurrency cap handles the\n  rest of the queue.\n- Between phases, read the results before launching the next one.\n- Schedule a check-in (`send_later`, ~45 min) during long runs so a wedged agent or a leaked dev\n  server gets noticed. Check `ps` for stray `reflex run` processes and commit finished clusters.\n- When the workflow completes, its full structured result is in the task output file; parse it for\n  the report rather than re-reading transcripts.\n",".claude/skills/prerelease-test/references/reporting.md":"# Reporting\n\n## FINDINGS.md\n\nThe audience is a maintainer deciding what blocks the release, and fix agents who will get handed\none finding and nothing else. Write for both: a summary that supports a go/no-go call, and findings\nself-contained enough to act on in isolation.\n\n```markdown\n# Findings — reflex <version> pre-release testing (<date>)\n\n<One paragraph on method: PyPI-only isolated venvs, end-to-end browser runs, previous-stable\nbaselines, independent adversarial verification of every claimed issue. Agent count.>\n\n## Versions under test\n<Every package and version, noting which are new in this train and that each is published.>\n<Environment: OS, CPU/RAM, node/bun, python versions, browser.>\n\n## Executive summary\n<What works — name the headline changelog items verified.>\n<What blocks — the short list, with severity.>\n<Severity histogram, and the count of refuted claims.>\n\nIndex:\n- FINDING-001: <title> (SEVERITY)\n- ...\n\n## FINDING-00N: <title> (SEVERITY)\n\n- Cluster: `<cluster>` | Regression vs <prev stable>: yes/no | Verifier: CONFIRMED\n- Repro: <exact commands/steps, self-contained>\n- Evidence: <log excerpt, console error, screenshot path>\n- Root cause (verifier analysis): <file:line and mechanism, when known>\n- Verification notes: <what the independent reproducer found>\n\n## Refuted / reclassified claims\n- **<title>** (`<cluster>`): <why it is not an actionable defect for this release>\n\n## Cluster summaries\n### `<cluster>` (pass:N, anomaly:N, fail:N)\n<2-4 sentences: what was built, what was verified, what was found.>\n```\n\nTwo things carry disproportionate weight and are easy to skip:\n\n- **The refuted list.** It shows the findings were filtered, which is why a maintainer can trust the\n  ones that remain. Never quietly drop a refuted claim.\n- **Regression status on every finding.** \"Broken in both versions\" and \"newly broken\" lead to\n  opposite decisions, and the reader cannot recover that from the description.\n\n## RELEASE_PLAN.md\n\n```markdown\n# Release plan — what blocks <version> vs what gets filed\n\n## Already in flight\n| PR | Covers | Gap check |\n<For each open PR, which findings it addresses and — importantly — what it does NOT cover.>\n\n## Fix before release\n### Security\n### Confirmed regressions\n### High impact and/or trivially small\n<Each item: finding ref, one-line rationale tied to the rubric, and the shape of the fix.>\n\n## File as issues, fix after release\n### <this repo>\n### <downstream repo>\n\n## Decisions needed from a maintainer\n<Behavior changes that are either bugs or missing changelog entries — their call, not yours.>\n\n## Suggested sequencing\n<Order of PRs, noting which can land in parallel and which touch the same files.>\n```\n\nThe rubric (confirmed regression / security / significant-impact-or-trivial) is in `SKILL.md`.\nApply it visibly: each entry should say which arm of the rubric put it there, so the maintainer can\ndisagree with a specific judgment rather than the whole list.\n\n## Filing issues\n\nFor post-release items: search for duplicates first (2–3 keyword variants, open *and* closed), then\nfile with a self-contained repro, observed vs expected, environment, a note that it came from\n`<version>` pre-release testing, and a pointer to the artifacts branch and cluster directory.\nMirror `.github/ISSUE_TEMPLATE/bug_report.md` where it fits.\n\n## If the user asks for the fixes afterwards\n\nThat is a separate engagement. What worked well:\n\n- **One PR per finding**, branched from current `main`, in its own git worktree so parallel fix\n  agents never collide.\n- **Regression test first**: write it, show it failing against unfixed `main`, then fix, then show\n  it passing. Report both states in the PR body — a reviewer should not have to take it on faith.\n- **News fragment** under the right package's `news/` directory. The changelog CI gate checks per\n  package: a fix touching `packages/reflex-base/` needs a fragment in\n  `packages/reflex-base/news/`, and a root-only fragment will fail the gate.\n- **Adversarial review of each PR** before handing it over: an independent agent re-runs the\n  regression test against unfixed source to confirm it actually pins the bug, and checks repo\n  conventions. This catches PRs whose test passes either way.\n- PR body: cite the FINDING number and that it came from pre-release testing, describe the defect\n  mechanism, the fix, and the test plan including the failing-before evidence.\n- Watch CI after opening (`subscribe_pr_activity`) and drive each PR to green.\n","AGENTS.md":"# Coding Agent Guidelines\n\nReflex: Python web **framework** compiling to React. Monorepo using uv workspace — main package in `reflex/`, sub-packages in `packages/`, docs site in `docs/`.\n\n## Workflow\n\n1. **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.\n2. **Bugfixes:** write a regression test that fails before writing the fix.\n3. **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.\n\n## Commands\n\nUse `uv` for everything — never bare `python` or `python3`.\n\n```\nuv sync                                                          # install deps\nuv run pytest tests/units --cov --no-cov-on-fail --cov-report=   # unit tests (>=72% coverage)\nuv run pytest tests/integration                                  # integration tests (slow)\nuv run ruff check .                                              # lint\nuv run ruff format .                                             # format\nuv run pyright reflex tests                                      # type check\nuv run python scripts/check_min_deps.py                          # validate each package's declared minimum dep versions (pyright in isolated min-version envs; workspace siblings resolve from locally built wheels, all other deps from PyPI). CI passes --wheelhouse instead, reusing the build jobs' artifacts\nuv run python scripts/check_min_deps.py --check-dev-pins [pkg]    # fail if pkg (default: all) declares an unpublishable *.dev dependency pin (the publish workflow runs the same gate via `reflex-release check-dev-pins`)\nuv run reflex-release sync                                       # regenerate the release workflows after editing [tool.reflex-release] or the reflex-release templates\nuv run python scripts/make_pyi.py                                # regenerate .pyi stubs\nuv run pre-commit run --all-files                                # all pre-commit hooks\n```\n\n## Layout\n\n```\nreflex/                 # main framework package (app, state, compiler, components, utils, istate)\npackages/               # workspace sub-packages (reflex-base, reflex-components-*, reflex-docgen, reflex-components-internal)\ntests/units/            # unit tests, mirrors source tree\ntests/integration/      # Selenium integration tests (run in dev+prod modes)\n  tests_playwright/     # Playwright integration tests (preferred for new tests)\ntests/benchmarks/       # performance benchmarks\ndocs/                   # documentation site (separate workspace member)\n```\n\n## Code style\n\n- Concise, robust code. Reflex is a framework used in many ways — handle edge cases without unnecessary complexity.\n- 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.\n- Don't add expensive workarounds (e.g. `isinstance` checks) to paper over type-level problems — fix the root cause instead.\n- Don't repeat validation or be over-defensive; trust data that was already validated upstream.\n- Think in CPU cycles: avoid unnecessary data copies, redundant allocations, and gratuitous indirection.\n- Extract duplicated code into parameterized helpers.\n- No block comments (`# --- Section ---`, `# ============`). Plain inline comments only.\n- Be cautious creating new public APIs — they must be documented and supported long-term.\n- Google-style docstrings on all functions: one-line summary, optional detail sentence(s), then Args/Returns (or Yields)/Raises.\n- Prefer imports at the top of the module in isort order. Only use inline imports when necessary to avoid circular dependencies.\n\n## Testing\n\n- Write comprehensive tests for new/changed features; extend existing test files where possible.\n- Test functions at module level, not wrapped in classes.\n- **Unit tests:** `tests/units/`, run with `uv run pytest tests/units`.\n  - 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`).\n- **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.\n\n### Integration test patterns\n\nApps as factory functions, run via `AppHarness`:\n\n```python\ndef SomeApp():\n    import reflex as rx\n\n    class State(rx.State):\n        value: str = \"\"\n\n    def index():\n        return rx.box(rx.text(State.value))\n\n    app = rx.App()\n    app.add_page(index)\n\n\n@pytest.fixture(scope=\"module\")\ndef some_app(tmp_path_factory) -> Generator[AppHarness, None, None]:\n    with AppHarness.create(\n        root=tmp_path_factory.mktemp(\"some_app\"), app_source=SomeApp\n    ) as harness:\n        yield harness\n```\n\nPlaywright tests use the `page` fixture and navigate to `harness.frontend_url`. Utilities in `tests/integration/utils.py` (polling, event ordering, storage).\n\n## .pyi stubs\n\nWhen 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.\n\n## CI workflows\n\nBranch rules require one check per workflow, listed in\n`.github/rulesets/main-required-checks.json`. Check names are matched literally —\nno wildcards — so two rules follow:\n\n- **A required workflow must not filter its `pull_request` trigger.** A workflow\n  a path filter skips never reports its checks, so a required check on it blocks\n  the merge forever. Filter in a `changes` job instead and gate the real jobs on\n  `if: needs.changes.outputs.run == 'true'` — a job skipped by `if:` reports as a\n  pass. `push` triggers may keep their filters; nothing gates a merge there. So\n  may a workflow that blocks no merge — absent from the ruleset and listed in\n  that test's `ADVISORY` — where the filter costs a run rather than a merge.\n- **Every merge-blocking workflow ends in a gate job** named `<workflow>-gate`,\n  which collapses it into one check name that matrix expansion cannot move. The\n  exception is a workflow with one job whose name cannot drift — `pre-commit`,\n  `changelog` — which the ruleset requires by that name (`DIRECTLY_REQUIRED` in\n  the test). A gate looks like:\n\n```yaml\n  unit-tests-gate:\n    needs: [changes, unit-tests, unit-tests-macos]  # every other job\n    if: always()  # not !cancelled(): a cancelled run would report a pass\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@... # v6.0.2\n        with:\n          persist-credentials: false\n      - uses: ./.github/actions/ci_gate\n        with:\n          needs: ${{ toJSON(needs) }}\n```\n\nAdding a job means adding it to the gate's `needs`; adding a workflow means\nadding its gate to the ruleset. `tests/units/test_workflow_gates.py` fails when\neither drifts. Every matrix leg blocks through its gate, pre-release Python\nversions included, so leave `continue-on-error` off a gated job. A workflow\ndisabled in the repository's Actions settings never reports, which no test can\nsee: disabling one means moving it to `ADVISORY` and out of the ruleset, or every\nmerge waits on it.\n\n## Changelog fragments\n\nUser-facing changes need a news fragment in the `news/` directory of each\npackage they touch (the repo root's `news/` for `reflex`), named\n`+<slug>.<type>.md`. Putting the PR number in the name (`<PR number>.<type>.md`)\nis optional: the release process renames an orphan fragment when it can identify\nthe PR that added it, so its entry links to that PR. Don't push a commit just to\nrename one. Types: `breaking`, `deprecation`, `feature`, `bugfix`,\n`performance`, `docs`, `misc`.\n\nWrite for external downstream users, not for reviewers. Every entry links to\nits PR, so motivation, narrative, and implementation details belong in the PR\nand the commit message — a reader who wants them will follow the link. Keep the\nfragment to a sentence or two saying what changed and what it means for a user:\n\n> Reduce published wheel and sdist size by removing misplaced generated artifacts.\n\nBrevity is about the narrative, not the substance: whatever is genuinely useful\ndownstream belongs in the fragment. A brief usage example for a new feature, or\nthe before/after of converting deprecated usage to the supported style, earns\nits place. Once it runs past a few sentences and a small code block, it is\ndocumentation — write it under `docs/` and let the fragment link there.\n\nCI requires a fragment for every package whose source the PR touches; the\n`skip-changelog` label waives it for changes that are genuinely not user-facing.\n\n## Sibling dependency floors\n\nWhen a package needs an unreleased change in a workspace sibling, raise its\nfloor on that sibling to the `.dev0` of the sibling's next version. Every\npackage derives its version with `bump = true`, so each commit after its newest\ntag builds as a dev release of that next version:\n\n- after `reflex-base-v0.9.12`: `reflex-base >= 0.9.13.dev0`\n- after `reflex-components-core-v0.9.10.post1`: `reflex-components-core >= 0.9.10.post2.dev0`\n\nSuch a floor excludes every release up to that tag and is met by every later\ncommit, so check-min-deps passes. A post release of the sibling cut after the\nfloor was written leaves main building below it; re-floor at that post release.\nReleasing the dependent lifts it to the first\npublished version that satisfies it (see `packages/reflex-release/README.md`,\n\"Dependency pins across a release\"). A floor the workspace can't meet fails\ncheck-min-deps with \"builds as ... here\".\n\n## Breaking changes and deprecation\n\nReflex has downstream users — don't break them. Provide a fallback path during deprecation.\n\n**Runtime warning** via `console.deprecate()`:\n```python\nfrom reflex_base.utils import console\n\nconsole.deprecate(\n    feature_name=\"OldFeature\",\n    reason=\"Use NewFeature instead.\",\n    deprecation_version=\"<next dot version of latest git tag>\",\n    removal_version=\"1.0\",\n)\n```\nSet `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.\n\n**Type-level deprecation** for deprecated methods/overloads using `typing_extensions.deprecated`, always inside a `TYPE_CHECKING` guard to avoid double warnings:\n```python\nfrom __future__ import annotations\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from typing_extensions import deprecated\n\n    @deprecated(\"Use new_method() instead\")\n    def old_method(self) -> str: ...\n```\n\n## Checklist\n\nBefore submitting:\n1. Tests pass with adequate coverage\n2. `uv run ruff check .` and `uv run ruff format .` clean\n3. `uv run pyright reflex tests` passes\n4. `pyi_hashes.json` updated if components changed\n5. Documentation updated if user-facing behavior changed\n6. News fragment added for user-facing changes\n7. Deprecation warnings added if breaking changes introduced\n","CLAUDE.md":"AGENTS.md","packages/hatch-reflex-pyi/README.md":"# hatch-reflex-pyi\n\nHatch build hook that generates .pyi stubs for Reflex component packages.\n","packages/integrations-docs/README.md":"# reflex-integrations-docs\n\nReflex Integrations Docs.\n","packages/integrations-docs/src/integrations_docs/docs/airtable.md":"---\ntags: Data Infrastructure\ndescription: Connect your apps to Airtable to read, create, and update records in real time.\n---\n# Airtable Integration\n\nThe **Airtable Integration** lets your apps interact with Airtable bases to **store, fetch, and update structured data** directly from workflows, user actions, or automated triggers. Perfect for managing dynamic content, customer data, or workflows without complex backend setup.\n\n\n## What You Can Do\n\nWith the Airtable Integration, your app can:\n\n* Read and display data from Airtable bases\n* Create new records dynamically from user actions\n* Update or delete records through workflows\n* Power AI experiences with live database content\n* Sync structured data without hosting your own database\n\n## Step 1: Get Your Airtable API Key\n\n1. Go to [Airtable](https://airtable.com/).\n2. Log in or create a free account.\n3. Navigate to [**Developer Hub**](https://airtable.com/create/tokens) from your account menu.\n4. Under **Personal access tokens**, click **Create token**.\n5. Add the appropriate scopes (e.g. `data.records:read` and `data.records:write`).\n6. Copy your API token.\n   * Example: `patxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n\n1. Click the **Settings** gear icon and navigate to the **Integrations** tab.\n2. Find and enable the **Airtable** integration.\n3. Paste your **API Key** in the input field.\n4. Click **Connect** to confirm the connection.\n\n## Step 3: Use in Your Workflows\n\nOnce connected, you can use Airtable actions in your app to:\n\n* Fetch records to display dynamic lists\n* Add user submissions as new rows\n* Update status fields or metrics from AI workflows\n\nand more.\n\n","packages/integrations-docs/src/integrations_docs/docs/anthropic.md":"---\ntags: AI\ndescription: Connect your apps to Anthropic's Claude models for advanced AI capabilities.\n---\n# Anthropic Integration\n\nThe **Anthropic Integration** allows your app to use [Anthropic’s Claude models](https://www.anthropic.com/claude) for tasks such as text generation, summarization, reasoning, and other advanced AI capabilities. Once connected, you can call Claude directly from your workflows, UI actions, or automated triggers.\n\n\n## Step 1: Obtain an Anthropic API Key\n\n1. Go to the [Anthropic Console](https://console.anthropic.com/).\n2. Navigate to **API Keys** in your account settings.\n3. Click **Create Key** and give it a descriptive name (e.g., “AI Builder”).\n4. Copy the generated key.\n\n   * **Example:** `sk-ant-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Anthropic** in your app settings.\n2. Paste your **Anthropic API Key** in the input field.\n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Claude for AI-powered features across workflows and components.\n\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Anthropic API key in public code repositories.\n* **Use environment-specific keys:** Separate dev, staging, and production keys help manage access and security.\n* **Secure API access:** The key allows your app to interact with Anthropic endpoints securely and efficiently.\n\n\n","packages/integrations-docs/src/integrations_docs/docs/aws.md":"---\ntags: Data Infrastructure\ndescription: Connect to Amazon Web Services (AWS) for cloud storage, databases, compute, AI/ML, and more.\n---\n# AWS Integration\n\nThe **AWS Integration** allows your app to connect to [Amazon Web Services (AWS)](https://aws.amazon.com/) — the world's most comprehensive cloud platform. Once connected, your app can access 200+ AWS services including storage, databases, compute, AI/ML, and more using the boto3 SDK.\n\n## What You Can Do\n\nWith AWS integration, your app can:\n- **S3 (Object Storage):** Upload, download, and manage files in S3 buckets. Generate presigned URLs for secure file access. Works with S3-compatible services like MinIO, Cloudflare R2, and DigitalOcean Spaces.\n- **DynamoDB (NoSQL Database):** Store and query data in a fully managed, serverless NoSQL database with single-digit millisecond performance.\n- **Lambda (Serverless Functions):** Invoke serverless functions, run code without managing servers, and build event-driven applications.\n- **SES (Email Service):** Send transactional emails, marketing emails, and notifications with high deliverability.\n- **SNS (Notifications):** Send push notifications, SMS, and email messages to users across multiple channels.\n- **SQS (Message Queues):** Build distributed, decoupled systems with reliable message queuing.\n- **Rekognition (Computer Vision):** Analyze images and videos for object detection, facial analysis, text extraction, and content moderation.\n- **Comprehend (NLP):** Extract insights from text using natural language processing for sentiment analysis, entity recognition, and topic modeling.\n- **Bedrock (AI Models):** Access foundation models from AI21 Labs, Anthropic, Cohere, Meta, Stability AI, and Amazon for generative AI applications.\n- **And 200+ more services:** EC2, RDS, CloudWatch, Polly, Textract, Translate, and many others.\n\n## Step 1: Obtain AWS Credentials\n\n1. Log in to the [AWS Console](https://console.aws.amazon.com/).\n\n2. **Create IAM credentials:**\n   - Navigate to **IAM (Identity and Access Management)**.\n   - Click **Users** → **Add user** or select an existing user.\n   - Attach policies based on the AWS services you plan to use:\n     - **S3:** `AmazonS3FullAccess` or custom S3 policy\n     - **DynamoDB:** `AmazonDynamoDBFullAccess` or custom DynamoDB policy\n     - **Lambda:** `AWSLambdaFullAccess` or custom Lambda policy\n     - **SES:** `AmazonSESFullAccess` or custom SES policy\n     - **Multiple services:** Attach multiple policies or create a custom policy combining permissions\n\n   **Example custom policy for S3 + DynamoDB:**\n   ```json\n   {\n     \"Version\": \"2012-10-17\",\n     \"Statement\": [\n       {\n         \"Effect\": \"Allow\",\n         \"Action\": [\n           \"s3:PutObject\", \"s3:GetObject\", \"s3:DeleteObject\", \"s3:ListBucket\",\n           \"dynamodb:PutItem\", \"dynamodb:GetItem\", \"dynamodb:Query\", \"dynamodb:Scan\"\n         ],\n         \"Resource\": [\n           \"arn:aws:s3:::YOUR_BUCKET_NAME/*\",\n           \"arn:aws:dynamodb:YOUR_REGION:YOUR_ACCOUNT_ID:table/*\"\n         ]\n       }\n     ]\n   }\n   ```\n\n3. **Generate access keys:**\n   - Under **Security credentials**, click **Create access key**.\n   - Choose **Application running outside AWS** as the use case.\n   - Copy your **Access Key ID** and **Secret Access Key**.\n\n   **Example credentials:**\n   * **Access Key ID:** `AKIAIOSFODNN7EXAMPLE`\n   * **Secret Access Key:** `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add AWS** in your app settings.\n2. Enter your **AWS Access Key ID** and **AWS Secret Access Key**.\n3. **(Optional)** Select your **AWS Region** (e.g., `us-east-1`, `eu-west-1`). Defaults to `us-east-1`.\n4. **(Optional)** Enter an **AWS Endpoint URL** if using S3-compatible services:\n   - **MinIO:** `http://localhost:9000` or your MinIO server URL\n   - **Cloudflare R2:** `https://<account-id>.r2.cloudflarestorage.com`\n   - **DigitalOcean Spaces:** `https://<region>.digitaloceanspaces.com`\n   - Leave blank for standard AWS services.\n5. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can access AWS services using boto3.\n\n## Important Notes\n\n* **IAM permissions:** Ensure your IAM user has the necessary permissions for the AWS services you plan to use. Attach service-specific policies (e.g., `AmazonS3FullAccess`, `AmazonDynamoDBFullAccess`, `AWSLambdaFullAccess`) or create custom policies with least-privilege access.\n* **AWS Region:** Most AWS services are region-specific. Select the correct region where your resources are located (e.g., S3 buckets, DynamoDB tables, Lambda functions).\n* **Cost management:** Monitor AWS usage and costs through the AWS Billing Dashboard. Set up billing alerts to avoid unexpected charges.\n* **Security:** Rotate your access keys regularly and enable MFA for AWS console access. Apply least-privilege IAM policies to limit permissions to only what's needed.\n* **S3-compatible services:** For S3 operations, this integration works with S3-compatible storage like MinIO (self-hosted), Cloudflare R2 (zero egress fees), and DigitalOcean Spaces. Just provide the custom endpoint URL in the configuration.\n* **Service availability:** Not all AWS services are available in all regions. Check the [AWS Regional Services List](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/) for service availability.\n","packages/integrations-docs/src/integrations_docs/docs/azure_auth.md":"---\ntags: Authentication\ndescription: Integrate Azure for secure authentication and access management within your application.\n---\n# Azure Auth Manager Integration\n\nThe **Azure Auth Manager Integration** allows your app to authenticate users through Microsoft Azure Active Directory (Azure AD). This integration provides secure OAuth 2.0 authentication and supports multi-tenant applications with customizable tenant access.\n\n## Step 1: Set Up Azure App Registration\n\nBefore connecting, you need to register your app in Azure Portal:\n\n1 - Go to [Azure Portal](https://portal.azure.com) → **App Registrations**\n\n2 - Click **New registration** as shown in the image below:\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_1.webp)\n\n3 - Register your app. Ensure that for the Redirect URI you select **Web** and enter the following URI that you find in the Azure Auth Manager integration settings in AI Builder:\n   ```\n   https://{your-sandbox}/authorization-code/callback\n   ```\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_2.webp)\n\n4 - On the next page get your `client_id` (`AZURE_CLIENT_ID`) and `tenant_id` (`AZURE_VALID_TENANT_IDS`) from the **Overview** tab.\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_3.webp)\n\n5 - Next click `Add a certificate or secret` and copy the generated secret value (`AZURE_CLIENT_SECRET`).\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_4.webp)\n\n\n## Step 2: Configure the Integration\n\n1. Go to the **Integrations** section in your app settings by clicking **`@`** and then clicking the **Integrations** tab at the top.\n2. Click **Add** next to Azure Auth Manager.\n3. Fill in the credential fields:\n   - Enter your Azure Client ID\n   - Enter your Azure Client Secret\n   - Enter valid tenant IDs (comma-separated for multiple tenants)\n4. Click **Connect** to save the integration.\n\nYour app can now authenticate users through Azure AD with secure OAuth 2.0 flow.\n","packages/integrations-docs/src/integrations_docs/docs/cartesia.md":"---\ntags: AI\ndescription: Add Cartesia’s powerful text-to-speech capabilities for realistic, real-time voice output and audio experiences.\n---\n# Cartesia Integration\n\nThe **Cartesia Integration** allows your app to generate **high-quality, realistic speech from text** using Cartesia’s advanced voice models. Once connected, you can easily add real-time voice capabilities to workflows, user interactions, and automated experiences.\n\n\n## Step 1: Obtain a Cartesia API Key\n\n1. Go to the [Cartesia Console](https://www.cartesia.ai/).  \n2. Log in or create an account.  \n3. Navigate to **API Keys** in your account settings.  \n4. Click **New**, give it a descriptive name (e.g., “AI Builder”), and copy it.  \n   - Example: `sk_car_xxxxxxxxxxxxx`\n\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Open your app and go to **Integrations → Add Cartesia**.  \n2. Paste your **Cartesia API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.  \n\nOnce connected, your app can convert text to speech seamlessly in real time or through workflows.\n\n\n\n## Step 3: Notes\n\n- **Secure API Access:** Keep your Cartesia API key safe. Do not hardcode it in public code.  \n- **Environment isolation:** Use different keys for dev, staging, and production to ensure clean separation.  \n- **Low latency:** Cartesia supports real-time streaming for conversational experiences.  \n- **Usage management:** Monitor your Cartesia dashboard for quotas, billing, and usage insights.\n\n","packages/integrations-docs/src/integrations_docs/docs/cohere.md":"---\ntags: AI\ndescription: Add Cohere’s language models for text generation, classification, retrieval, embeddings, and more.\n---\n# Cohere Integration\n\nThe **Cohere Integration** allows your app to use [Cohere’s](https://cohere.com) state-of-the-art language models for natural language understanding and generation. Once connected, your app can power search, summarization, embeddings, classification, and conversational AI features directly from workflows and triggers.\n\n\n## Step 1: Obtain a Cohere API Key\n\n1. Go to the [Cohere Dashboard](https://dashboard.cohere.com/).  \n2. Log in or create an account.  \n3. Navigate to **API Keys** in your account settings.  \n4. Click **Create Key**, give it a descriptive name (e.g., “AI Builder”), and copy the key.  \n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Cohere** in your app settings.  \n2. Paste your **Cohere API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.  \n\nOnce connected, your app can access Cohere’s endpoints for language tasks like embeddings, classification, chat, and more.\n\n\n## Step 3: Notes\n\n- **Secure API Access:** Keep your Cohere API key private — do not hardcode it in public repositories.  \n- **Environment separation:** Use different keys for development, staging, and production environments.  \n- **Performance:** Cohere’s models support fast inference for production-ready experiences.  \n- **Observability:** Use the Cohere dashboard to monitor usage, quotas, and request logs.\n\n","packages/integrations-docs/src/integrations_docs/docs/database.md":"---\ntags: Data Infrastructure\ndescription: Connect Reflex Build apps to PostgreSQL, MySQL, MSSQL, or SQLite databases.\n---\n# Database Integration\n\nThe Database Integration connects Reflex Build apps to an existing SQL database. When you enable the connection for an app, Reflex Build can inspect its schema and use that structure while generating the app.\n\n## Supported Databases\n\n- **PostgreSQL**\n- **MySQL**\n- **MSSQL** (Microsoft SQL Server)\n- **SQLite**\n\n## Add a Database Integration\n\n1. Open **Integrations** from the project sidebar.\n2. Select **Add Integration**.\n3. Search for and select **Database**.\n4. Configure the connection using **Connection Details** or **Database URI**.\n5. Optionally enter an integration name to distinguish this connection from others in the project.\n6. Select **Save Changes**.\n\nThe integration is saved at the project level. Open an app's **Integrations** panel to enable it for that app when needed.\n\n## Connection Details\n\nUse **Connection Details** to enter each part of the connection separately.\n\nFor PostgreSQL, MySQL, and MSSQL, choose the database type and enter:\n\n- `hostname`: the database server address.\n- `port`: defaults to `5432` for PostgreSQL, `3306` for MySQL, or `1433` for MSSQL.\n- `username` and `password`: the database credentials.\n- `database_name`: the database to connect to.\n\nFor MSSQL, **Trust Server Certificate** skips certificate identity validation. Use it only as a temporary workaround for an untrusted or self-signed server certificate, and prefer configuring a certificate that the client trusts.\n\nFor SQLite, select **SQLite** and enter an HTTP or HTTPS **SQLite Download URL**. Reflex Build downloads the database file before using it.\n\n## Database URI\n\nUse **Database URI** when you have a complete connection URI for one of the supported database types. For example:\n\n```text\npostgresql://username:password@hostname:5432/database_name\n```\n\nEnter the URI in `db_url`, then select **Save Changes**. Reflex Build selects the database driver automatically. Include provider-required connection options as query parameters when needed.\n\n## Connect through an SSH Tunnel\n\nUse an SSH tunnel when the database is on a private network but can be reached through a bastion host. This option is available for PostgreSQL, MySQL, and MSSQL in both connection modes. It is not available for SQLite.\n\n1. Enter the database connection details or URI. Keep the database hostname and port set to the address the bastion host uses to reach the database.\n2. Turn on **Connect via SSH tunnel**.\n3. Enter the `ssh_hostname`, `ssh_port` (usually `22`), and `ssh_username` for the bastion host.\n4. Paste the corresponding PEM-formatted **SSH private key**.\n5. Select **Save Changes**.\n\nThe SSH account must allow port forwarding to the database host and port. Use a dedicated, restricted SSH key and database user for Reflex Build.\n\n```md alert warning\n# Keep credentials private\n\nEnter database passwords, connection URIs, and SSH private keys only in the integration form. Do not put them in prompts, knowledge, source code, or screenshots.\n```\n\n## Enable the Integration for an App\n\nOpen the app's **Integrations** panel and enable the saved database connection. Reflex Build then connects to the database and, when the app does not already have a model file, creates the app's data models from the schema.\n\nIf the connection fails, check that:\n\n- The database or bastion host is reachable.\n- The ports are open and the credentials are valid.\n- The database user can read the schema and has only the data permissions the app needs.\n- The SSH user can forward traffic to the database when tunneling is enabled.\n\n```md alert\n# NoSQL Databases\n\nUse the dedicated MongoDB integration when applicable. For another NoSQL database, add its Python SDK or configure a custom integration; the Database Integration supports SQL databases.\n```\n","packages/integrations-docs/src/integrations_docs/docs/databricks.md":"---\ntags: Data Infrastructure\ndescription: Connect with Databricks to run data pipelines and advanced analytics seamlessly.\n---\n\n\n# Databricks Integration\n\nThe **Databricks Integration** allows your app to connect to [Databricks](https://www.databricks.com/) for secure data access, querying, and analytics. Once connected, you can run SQL queries, retrieve results, and power data-driven workflows directly from your app.\n\n## What You Can Do\n\nWith Databricks, your app can:\n- Connect securely to your Databricks workspace.  \n- Run **SQL queries** or fetch data programmatically.  \n- Build **dashboards and data visualizations** on top of your Databricks tables.  \n- Automate workflows triggered by new or updated data.  \n- Combine Databricks with AI models for advanced analytics.\n\n\n\n## Step 1: Get Your Databricks Credentials\n\n### 1 - Log in to your [Databricks Workspace](https://databricks.com/).\n\n### 2 - Get your **DATABRICKS_HOST** and **DATABRICKS_WAREHOUSE_ID**:\n\n   - Go to `SQL Warehouses` from the sidebar.\n   - Select your desired warehouse.\n   - Click `Connection details`.\n   - Copy the Server hostname (this is your **DATABRICKS_HOST**).\n   - Copy the HTTP path removing the `/sql/1.0/warehouses/` prefix (this is your **DATABRICKS_WAREHOUSE_ID**).\n\n![Databricks SQL Warehouse connection details](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_1.webp)\n\n### 3 - Get your **DATABRICKS_CATALOG** and **DATABRICKS_SCHEMA**:\n   - Click the SQL Editor from the sidebar.\n   - Choose the **DATABRICKS_CATALOG** and **DATABRICKS_SCHEMA** from the dropdowns as shown below.\n\n![Selecting Databricks catalog and schema in SQL Editor](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_4.webp)\n\n\n### 4 - Obtain your authentication credentials:\n\nThere are two methods to authenticate your app with Databricks: using interactive U2M **OAuth** or via registered M2M **Service Principal**. Choose one of the methods below to obtain the necessary credentials.\n\n\n`````md tabs\n\n## OAuth with Databricks\n\n#### Interactive Login with your Databricks Account\n\nIf your workspace administrator has already added Reflex as a Connected App in your Databricks workspace, you should see a \"Login with Databricks\" button after entering your DATABRICKS_HOST.\n\n\n## Service Principal\n\n#### M2M Service Principal (DATABRICKS_CLIENT_ID and DATABRICKS_CLIENT_SECRET)\n\n- Open the dropdown in the top right corner and select **Manage Account**.\n\n![Opening Manage Account in Databricks](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_1.webp)\n\n- Select `Users and Groups`\n\n![Selecting Users and Groups in Databricks account](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_2.webp)\n\n- Select the `Service Principals` tab and click `Add Service Principal`.\n\n![Adding a Databricks service principal](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_3.webp)\n\n- Fill in the details and click `Add Service Principal`.\n\n![Entering Databricks service principal details](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_4.webp)\n\n- Click the `Credentials and Secrets` tab and click `Generate Secret`.\n\n![Generating a Databricks service principal secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_5.webp)\n\n- Set a lifetime for the secrets and click `Generate`.\n\n![Setting Databricks secret lifetime](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_6.webp)\n\n- Copy the generated **DATABRICKS_CLIENT_ID** and **DATABRICKS_CLIENT_SECRET**.\n\n![Copying Databricks client ID and secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_7.webp)\n\n`````\n\n\n\n## Step 2: Configure the Integration in Your App\n\n1. In your app, go to **Integrations** and **Add Databricks**.\n2. Paste your **DATABRICKS_HOST**\n3. Select your authentication method:\n   - OAuth, if configured.\n   - Service Principal, provide the client ID and secret gathered previously.\n2. Paste or select your\n   1. **DATABRICKS_WAREHOUSE_ID**\n   2. **DATABRICKS_CATALOG**\n   3. **DATABRICKS_SCHEMA**  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, the AI Builder can execute queries directly against your Databricks environment.\n\n\n## Step 3: Notes\n\n* **Secure your token:** Never expose tokens in public code.  \n* **Permissions:** Ensure your token or service account has the required workspace and table permissions.\n* **Combine with AI:** Use query outputs to power models, summaries, or alerts in real time.\n\n\n## How to Enable Login as an Admin\n\n- Login to Databricks\n- Go to manage account\n\n![Opening Manage Account as Databricks admin](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_admin_auth_1.webp)\n\n- Go to **Settings** → **Apps Connections** → **Add new connection**\n\n![Adding a new app connection in Databricks settings](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_admin_auth_2.webp)\n\n- Give it a name, enter the redirect URL that Reflex Build provides, Click `All APIs` and uncheck `Generate a client secret` and then add.\n   - URL: `https://build.reflex.dev/_reflex_oidc_databricks/authorization-code/callback`\n\n![Configuring the Reflex redirect URL in Databricks](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_admin_auth_3.webp)","packages/integrations-docs/src/integrations_docs/docs/descope.md":"---\ntags: Authentication\ndescription: Add Descope’s identity and authentication platform to your apps to manage user sign-in, onboarding, MFA, SSO, and flows with ease.\n---\n# Descope Integration\n\nThe **Descope Integration** enables your app to leverage Descope’s full Customer Identity & Access Management (CIAM) features—visual authentication flows, identity management, SSO, MFA, tenant isolation, and more. Once set up, you can orchestrate secure user journeys across your application with minimal coding.\n\n\n```md alert warning\n# You must open your app in a new tab from the builder to test the Descope integration.\n```\n\n## What You Can Do\n\nWith Descope Integration, your app can:\n- Handle user sign-up, login, and passwordless flows seamlessly  \n- Enable multifactor authentication (MFA), passkeys, and social login  \n- Support single sign-on (SSO) via OIDC/SAML  \n- Manage users, roles, tenants, and permissions via management APIs  \n- Orchestrate onboarding, branding, and multi-tenant flows via drag-and-drop workflows  \n- Sync user data with tools like HubSpot or Segment via built-in connectors\n\n\n## Step 1: Obtain Descope Credentials\n\n![Descope Credentials](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/descope.webp)\n\n1. Log in to the [**Descope Console** (or sign up)](https://www.descope.com/sign-up).\n2. Create your first Project. \n3. Go to the Project page under Settings.\n4. Copy the `Project ID`.\n\n\n## Step 2: Configure the Integration in Your App\n\n1. In your app’s settings or integration dashboard, select **Add Descope**.  \n2. Enter your **PROJECT_ID**.  \n3. (Optional) Pick a **DESCOPE_FLOW_ID** (e.g. “sign-up-or-login”) and **SESSION_SECRET_KEY** or press the Clipboard Copy to use default values.  \n4. Click **Connect** to validate credentials and enable Descope features.\n\n![Descope Integration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/descope_2.webp)\n\n\n","packages/integrations-docs/src/integrations_docs/docs/gemini.md":"---\ntags: AI\ndescription: Connect your apps to Google’s Gemini models for advanced AI capabilities.\n---\n# Gemini Integration\n\nThe **Gemini Integration** allows your app to use [Google’s Gemini models](https://aistudio.google.com/) for text generation, reasoning, multimodal analysis, and other advanced AI capabilities. Once connected, you can call Gemini directly from your workflows, UI actions, or automated triggers.\n\n## Step 1: Obtain a Gemini API Key\n\n1. Go to [Google AI Studio](https://aistudio.google.com/).\n2. Navigate to **Get API Key** or create a new key for your project.\n3. Copy the generated key.\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Gemini** in your app settings.  \n2. Paste your **Gemini API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Gemini for AI-powered features across workflows and components.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Gemini API key in public code repositories.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys help manage access and security.  \n* **Secure API access:** The key allows your app to interact with Gemini endpoints securely and efficiently.\n","packages/integrations-docs/src/integrations_docs/docs/github.md":"---\ntags: Developer Tools\ndescription: Connect your app to GitHub to automate workflows, manage repositories, and integrate developer operations.\n---\n# GitHub Integration\n\nThe **GitHub Integration** lets your app connect directly to [GitHub](https://github.com) to automate actions, fetch data, and build powerful developer workflows. Once connected, your app can interact with repositories, issues, pull requests, and more.\n\n## What You Can Do\n\nWith GitHub, your app can:\n- Fetch and display repository data (commits, branches, issues, etc.).  \n- Create or update issues, pull requests, and discussions.  \n- Trigger workflows or CI/CD pipelines.  \n- Sync GitHub activity into your app’s dashboards or automations.  \n- Build custom developer tools using GitHub’s API.\n\n## Step 1: Generate a Personal Access Token\n\n1. Go to your [GitHub Settings](https://github.com/settings/tokens).  \n2. Navigate to **Developer settings → Personal access tokens**.  \n3. Click **Generate new token** (classic or fine-grained).  \n4. Select the required scopes (e.g., `repo`, `workflow`, `read:user`).  \n5. Copy the token.  \n   **Example token:**  \n```\nghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n```\n(Note: Replace the above value with your actual GitHub token)\n\n> 💡 Fine-grained tokens are recommended for better security.\n\n## Step 2: Configure the Integration in Your App\n\n1. In your app, go to **Integrations → Add GitHub**.  \n2. Paste your **GitHub Personal Access Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can start interacting with GitHub through workflows and actions.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Never expose your GitHub token in public code.  \n* **Use fine-grained permissions:** Limit access to only what’s needed.  \n* **API rate limits:** GitHub imposes API limits, so plan automations accordingly.  \n* **Combine with AI:** For example, auto-generate release notes from commits or summarize PRs with LLMs.\n\n","packages/integrations-docs/src/integrations_docs/docs/google_auth.md":"---\ntags: Authentication\ndescription: Enable secure authentication using Google sign-in and OAuth 2.0 workflows.\n---\n\n# Google Auth Integration\n\nThe **Google Auth Integration** allows your app to authenticate users using their Google accounts. This provides a secure, familiar login experience and simplifies user management.\n\n\n## Step 1: Create a Google OAuth Client\n\n1 - Go to the [Google Cloud Console](https://console.cloud.google.com/)\n\n2 - Navigate to **APIs & Services → Credentials**\n\n3 - Click **Create Credentials**\n\n![Creating credentials in Google Cloud Console](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_1.webp)\n\n4 - Choose **OAuth client ID**.\n\n![Choosing OAuth client ID credential type](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_2.webp)\n\n5 - Choose **Web Application** as the application type, name the application and enter your sandbox URL, which you get from the Google Auth integration panel, as the **Authorized JavaScript Origin** and **Authorized Redirect URIs**.\n\n![Configuring Google OAuth web application origins](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_3.webp)\n\n6 - Copy the generated **Client ID** (`GOOGLE_CLIENT_ID`) and **Client Secret** (`GOOGLE_CLIENT_SECRET`).\n\n![Copying Google client ID and secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_4.webp)\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Google Auth** in your app settings.\n2. Enter your **Google Client ID** and **Google Client Secret**.\n3. Save the integration. Your app is now configured to use Google Auth for login.\n\n## Step 3: Notes\n\n- The integration supports multiple environments (development, staging, production). Use environment-specific secrets for the client ID and secret.\n- Google Auth handles token refresh automatically when users log in via OAuth.\n- Users will see a standard Google login screen, ensuring familiarity and trust.\n- Ensure your app domain matches the authorized JavaScript origin and redirect URIs; otherwise, authentication will fail.\n","packages/integrations-docs/src/integrations_docs/docs/groq.md":"---\ntags: AI\ndescription: Connect your apps to Groq’s ultra-fast inference API for lightning-speed AI responses.\n---\n# Groq Integration\n\nThe **Groq Integration** allows your app to use [Groq’s API](https://groq.com/) for ultra-fast AI inference. Once connected, your app can leverage Groq’s hosted models (including open models like Llama 4 and Qwen) to power real-time workflows, chat experiences, and other AI-driven features.\n\n## Step 1: Obtain a Groq API Key\n\n1. Go to the [Groq Console](https://console.groq.com/).  \n2. Navigate to **API Keys** in your account settings.  \n3. Click **Create API Key** and give it a descriptive name (e.g., “AI Builder”).  \n4. Copy the generated key.\n   * **Example:** `gsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Groq** in your app settings.  \n2. Paste your **Groq API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Groq to deliver ultra-low latency AI responses across workflows and components.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Groq API key in public code repositories.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys help manage access and security.  \n* **Secure API access:** The key allows your app to interact with Groq endpoints securely and efficiently.\n","packages/integrations-docs/src/integrations_docs/docs/hubspot.md":"---\ntags: Data Infrastructure\ndescription: Connect your apps to HubSpot to manage contacts, companies, deals, and marketing workflows.\n---\n# HubSpot Integration\n\nThe **HubSpot Integration** allows your app to use [HubSpot](https://www.hubspot.com/) as a CRM and marketing automation platform. Once connected, your app can sync leads, manage contacts, update pipelines, and trigger workflows directly from user actions or automated events.\n\n## Step 1: Obtain a HubSpot Access Token\n\n1. Go to your [HubSpot Developer Account](https://developers.hubspot.com/).  \n2. Navigate to **App → Private Apps** in your account settings.  \n3. Click **Create Private App**, configure scopes (e.g., `crm.objects.contacts.read/write`, `crm.schemas.companies.read`), and save.  \n4. Copy the **Access Token** from the Auth tab.\n   * **Example:** `pat-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add HubSpot** in your app settings.  \n2. Paste your **HubSpot Access Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can sync and manage HubSpot data directly from workflows and UI actions.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Do not hardcode your HubSpot token in public code repositories.  \n* **Use environment-specific tokens:** Separate dev, staging, and production tokens to manage access.  \n* **Secure API access:** The token allows your app to interact with HubSpot endpoints securely and efficiently.\n\n","packages/integrations-docs/src/integrations_docs/docs/hugging_face.md":"---\ntags: AI\ndescription: Connect your apps to Hugging Face to access thousands of open models for text, vision, and multimodal tasks.\n---\n# Hugging Face Integration\n\nThe **Hugging Face Integration** allows your app to use [Hugging Face](https://huggingface.co/) models for a wide range of AI tasks — including text generation, embeddings, translation, classification, image processing, and more. You can integrate both hosted models (via API) or local open-source models through the Transformers library.\n\n## What You Can Do\n\nWith Hugging Face, your app can:\n- Access thousands of pre-trained **text, vision, and multimodal models**.  \n- Run **text generation**, summarization, translation, and classification tasks.  \n- Use **embeddings** for search, retrieval, and similarity.  \n- Deploy models locally with `transformers` or connect to hosted inference endpoints.  \n- Fine-tune or customize open models for your specific use cases.  \n- Integrate community and enterprise models seamlessly into workflows.\n\n## Step 1: Obtain a Hugging Face Access Token (Optional)\n\n1. Go to [Hugging Face](https://huggingface.co/).  \n2. Log in or create a free account.  \n3. Navigate to **Settings → Access Tokens**.  \n4. Click **Create New token**, set its scope, and copy it.\n   * **Example:** `hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Hugging Face** in your app settings.  \n2. Paste your **Hugging Face Access Token** if required.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Hugging Face models directly in workflows, UI actions, or automations.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Never expose your Hugging Face token in client-side code.  \n* **Use environment-specific tokens:** Separate dev, staging, and production access.  \n* **Open-source flexibility:** Models can be run fully locally or through Hugging Face’s hosted endpoints.  \n* **Broad ecosystem:** Hugging Face supports thousands of community and commercial models for rapid prototyping and production use.\n","packages/integrations-docs/src/integrations_docs/docs/langchain.md":"---\ntags: AI\ndescription: Connect your apps to Langchain for advanced AI capabilities.\n---\n# Langchain Integration\nThe **LangChain Integration** allows your app to leverage the power of [LangChain](https://langchain.com/), a popular open-source framework for building applications with large language models (LLMs). Once connected, your app can orchestrate complex AI workflows, chain together multiple model calls, and integrate with various data sources and tools seamlessly.\n\n\nYou can:\n\n* **Chain model calls together** to create multi-step reasoning flows.\n* **Connect multiple providers** (e.g., OpenAI, Anthropic, Gemini, Groq) through a single interface.\n* **Build intelligent agents** that can use tools, call APIs, or access external data sources dynamically.\n* **Work with structured data** by combining LLMs with databases, vector stores, and retrieval systems.\n* **Create RAG (Retrieval-Augmented Generation)** pipelines to ground model outputs in your own data.\n* **Integrate tools and memory** so models can reason over past interactions and context.\n* **Deploy reusable components** like prompt templates, chains, and agents for production-grade applications.\n\nLangChain essentially acts as a **“glue layer”** between language models, data, and logic — enabling teams to build more **powerful and reliable AI apps** without reinventing core orchestration features.\n\n\n## Configure the Integration in Your App\n\n1. Click the **Settings** gear icon and navigate to the **Integrations** tab.\n2. Find and enable the **LangChain** integration.\n\n","packages/integrations-docs/src/integrations_docs/docs/linear.md":"---\ntags: DevTools\ndescription: Connect your apps to Linear to manage issues, projects, and sprints directly from workflows.\n---\n# Linear Integration\n\nThe **Linear Integration** allows your app to connect to [Linear](https://linear.app/) to create, update, and track issues and projects seamlessly. Once connected, your app can trigger Linear actions from user interactions or automated workflows.\n\n## What You Can Do\n\nWith Linear, your app can:\n- **Create and assign issues** automatically from user actions or AI workflows.  \n- **Update status and priority** of tickets and projects.  \n- **Sync with sprints and cycles** to keep work organized.  \n- **Fetch project and issue data** for dashboards, summaries, or automation.  \n- **Integrate with other tools** like Slack or GitHub through workflows.  \n- Power intelligent workflows (e.g., auto-triage or auto-summarize bug reports).\n\n## Step 1: Obtain a Linear API Key\n\n1. Go to your [Linear account](https://linear.app/).  \n2. Navigate to **Workspace Settings → API**.  \n3. Click **Create API Key**, give it a name, and copy the key.\n\n   * **Example:** `lin_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Linear** in your app settings.\n2. Paste your **Linear API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can interact with Linear to automate issue tracking and project management.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Never expose your Linear API key in client-side code.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys.  \n* **Streamlined workflows:** Automate ticket creation, status updates, and reporting directly from your app.  \n* **Real-time visibility:** Fetch and sync project data to power internal tools or dashboards.\n\n","packages/integrations-docs/src/integrations_docs/docs/notion.md":"---\ntags: Data Infrastructure\ndescription: Connect your apps to Notion to create, update, and query pages, databases, and documents.\n---\n# Notion Integration\n\nThe **Notion Integration** allows your app to connect to [Notion](https://www.notion.so/) to manage content, automate workflows, and build dynamic interfaces on top of Notion workspaces. Once connected, your app can read and write pages, sync databases, and trigger actions based on user activity.\n\n## What You Can Do\n\nWith Notion, your app can:\n- **Create and update pages** in workspaces automatically.  \n- **Read and query databases** to power dashboards, workflows, or automations.  \n- **Sync structured content** like tasks, notes, or documentation with other tools.  \n- Trigger **actions from AI workflows** (e.g., creating meeting notes, logging issues).  \n- Integrate with other services (e.g., Slack, Linear, HubSpot) for seamless collaboration.\n\n## Step 1: Obtain a Notion API Token\n\n1. Go to the [Notion Developers](https://www.notion.so/my-integrations) page.  \n2. Click **+ New Integration**, give it a name, and copy the generated **Internal Integration Token**.  \n3. Share the integration with the relevant pages or databases in your workspace to grant access.\n\n   * **Example:** `ntn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Notion** in your app settings.  \n2. Paste your **Notion API Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can read and write to Notion directly from workflows and UI actions.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Never expose your Notion token in client-side code.  \n* **Use environment-specific tokens:** Separate dev, staging, and production access.  \n* **Granular permissions:** Only share the integration with the pages or databases it needs to access.  \n* **Powerful building block:** Use Notion as a single source of truth for content, tasks, or structured data.\n\n","packages/integrations-docs/src/integrations_docs/docs/okta_auth.md":"---\ntags: Authentication\ndescription: Use Okta for secure identity and access management via Single Sign-On provisioning.\n---\n\n# Okta Auth Manager Integration\n\nThe **Okta Auth Manager Integration** allows your app to authenticate users through [Okta](https://okta.com). This integration provides secure OAuth 2.0 / OIDC authentication and supports multi-tenant environments with customizable access policies.\n\n\n## What You Can Do\n\nWith Okta, your app can:\n- Authenticate users securely through Okta’s identity platform.  \n- Enable **SSO** for enterprise users.  \n- Manage user roles, groups, and access permissions.  \n- Protect sensitive data and actions with **OAuth 2.0** and **OpenID Connect (OIDC)**.  \n- Integrate with other identity workflows like MFA or adaptive policies.\n\n\n## Step 1: Set Up Okta OIDC App\n\nBefore connecting, you need to create an OIDC application in the Okta Admin Console:\n\n1 - Go to [Okta Admin Console](https://login.okta.com) → **Applications** → **Applications**\n\n\n2 - Click **Create App Integration**\n\n![Creating an Okta app integration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_1.png)\n\n3 - Select **OIDC – OpenID Connect** and choose **Web Application**\n\n![Selecting OIDC web application in Okta](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_2.png)\n\n4 - Configure your app settings:\n   - **Allow wildcard * in sign-in redirect URIs**\n   - **Sign-in redirect URIs** found in the Okta Auth Manager integration settings in AI Builder:\n     `https://{your-sandbox}/authorization-code/callback`\n   - **Sign-out redirect URIs**:\n     `https://{your-sandbox}`\n   - Assign to the correct **Group** or **Everyone** depending on your access control\n\n![Configuring Okta sign-in redirect URIs](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_3.png)\n\n5 - Save the app integration.\n\n6 - Copy your **Client ID** (`OKTA_CLIENT_ID`) and **Client Secret** (`OKTA_CLIENT_SECRET`) from the app settings.\n\n![Copying Okta client ID and secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_4.png)\n\n\n## Step 2: Finding Your Okta Issuer URI\n\n1. In the Okta Admin Console, go to **Security** → **API** → **Authorization Servers**\n2. Click on the **default** server and copy the **Issuer URI**.\n3. Remove the trailing `/oauth2/default` from the URI to get your **Okta Issuer URI** (`OKTA_ISSUER_URI`).\n\nExample:\n\nIf your Issuer URI is `https://{yourOktaDomain}.okta.com/oauth2/default`\n\nUse `https://{yourOktaDomain}.okta.com`\n\n![Finding the Okta issuer URI](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_5.png)\n\n\n> **Note:** Always use separate Okta apps for dev, staging, and production environments to avoid mixing credentials.\n\n\n## Step 3: Configure the Integration\n\n1. Go to the **Integrations** section in your app settings by clicking **`@`** and then selecting the **Integrations** tab.\n2. Click **Add** next to **Okta Auth Manager**.\n3. Fill in the credential fields:\n   - Enter your Okta Client ID\n   - Enter your Okta Client Secret\n   - Enter your Okta Issuer URI\n4. Click **Connect** to save the integration.\n\nYour app can now authenticate users through Okta using the secure OAuth 2.0 / OIDC flow.\n","packages/integrations-docs/src/integrations_docs/docs/openai.md":"---\ntags: AI\ndescription: Connect to OpenAI's powerful language models for text generation, analysis, and more.\n---\n# OpenAI Integration\n\nThe **OpenAI Integration** allows your app to use OpenAI APIs for features such as text generation, embeddings, and other AI-powered functionality.\n\n## Step 1: Obtain an OpenAI API Key\n\n1. Go to the [OpenAI Platform](https://platform.openai.com/).\n2. Navigate to **API Keys** in your account settings.\n3. Click **Create new secret key**.\n4. Copy the generated key.\n   - Example: `sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add OpenAI Integration** in your app settings.\n2. Enter your **OpenAI API Key** in the input field.\n3. Save the integration. Your app is now ready to make OpenAI API requests.\n\n---\n\n## Step 3: Notes\n\n- Keep your OpenAI key secure; do **not** hardcode it in public code repositories.\n- Use environment-specific secrets if you have separate development, staging, and production environments.\n- The key allows your app to interact with OpenAI endpoints securely and efficiently.\n","packages/integrations-docs/src/integrations_docs/docs/overview.md":"```python exec\nfrom pcweb.pages.integrations.integration import integration_page\n```\n\n```python eval\nintegration_page()\n```\n","packages/integrations-docs/src/integrations_docs/docs/perplexity.md":"---\ntags: AI\ndescription: Connect your apps to Perplexity to power real-time, retrieval-augmented AI experiences.\n---\n# Perplexity Integration\n\nThe **Perplexity Integration** allows your app to use [Perplexity](https://www.perplexity.ai/) to deliver fast, accurate, retrieval-augmented answers from the web and trusted sources. Once connected, you can use Perplexity to enhance search, summarization, and real-time knowledge in your workflows.\n\n## What You Can Do\n\nWith Perplexity, your app can:\n- **Retrieve real-time information** from the web to ground model outputs.  \n- **Generate concise summaries** and answers with citations.  \n- Power **search experiences**, research assistants, and contextual AI features.  \n- **Combine Perplexity with other models** for hybrid workflows (e.g., retrieval + reasoning).  \n- Enable **trusted, source-backed outputs** for more accurate responses.\n\n## Step 1: Obtain a Perplexity API Key\n\n1. Go to the [Perplexity](https://www.perplexity.ai/).  \n2. Log in or create an account.  \n3. Navigate to **Account → API → [API Keys](https://www.perplexity.ai/account/api/keys)**.  \n4. Click **Generate Key** and copy the generated key.\n\n   * **Example:** `pplx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Perplexity** in your app settings.  \n2. Paste your **Perplexity API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Perplexity for retrieval-augmented AI features across workflows and components.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Perplexity API key in public code repositories.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys for better control.  \n* **Secure API access:** The key allows your app to interact with Perplexity endpoints securely and efficiently.  \n* **Real-time power:** Perplexity is ideal for use cases where freshness and factual grounding matter.\n","packages/integrations-docs/src/integrations_docs/docs/replicate.md":"---\ntags: AI\ndescription: Connect your apps to Replicate to run and deploy open-source machine learning models with ease.\n---\n# Replicate Integration\n\nThe **Replicate Integration** allows your app to use [Replicate](https://replicate.com/) to run open-source AI models in the cloud without managing infrastructure. Once connected, you can use Replicate to generate text, images, audio, and more — directly from workflows and UI actions.\n\n## What You Can Do\n\nWith Replicate, your app can:\n- Run open-source **AI models** without GPU or hosting setup.  \n- Access models for **text generation**, **image generation**, **audio**, and **multimodal tasks**.  \n- Automate workflows like content generation, data processing, or AI-powered features.  \n- Use prebuilt models or deploy your own custom models.  \n- Scale effortlessly with serverless infrastructure.\n\n## Step 1: Obtain a Replicate API Token\n\n1. Go to the [Replicate Dashboard](https://replicate.com/account).  \n2. Log in or create an account.\n3. Navigate to the **API Tokens** section.  \n4. Copy your **API Token** from the account page.\n\n   * **Example:** `r8_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Replicate** in your app settings.  \n2. Paste your **Replicate API Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can call Replicate models directly in workflows, UI actions, or automations.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Do not hardcode your Replicate token in public code repositories.  \n* **Use environment-specific tokens:** Separate dev, staging, and production environments for security.  \n* **Secure API access:** The token allows your app to interact with Replicate endpoints safely and efficiently.  \n* **Model flexibility:** You can use community models or deploy your own for full control.\n","packages/integrations-docs/src/integrations_docs/docs/resend.md":"---\ntags: Communication\ndescription: Send transactional and automated emails directly from your AI-generated applications using Resend.\n---\n# Resend Integration\n\nThe **Resend Integration** allows your AI-generated apps to send emails directly from workflows, user actions, or automated triggers — perfect for notifications, confirmations, or any email-based communication your app needs.\n\n\n## What You Can Do\n\nWith the Resend Integration, your app can:\n- Send automated transactional emails\n- Notify users of important events (signups, job completions, etc.)\n- Integrate email sending into AI workflows\n- Use dynamic variables in your message body (e.g. user name, order ID)\n\n## Step 1: Get Your Resend API Key\n\n1. Go to [Resend](https://resend.com/).\n2. Log in or create a free account.\n3. Navigate to **API Keys** from the dashboard sidebar.\n4. Click **Create API Key**, give it a name (e.g. “AI Builder”), and copy it.\n   - Example: `re_xxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Open your app in the **AI Builder**.\n2. Click the **Settings** gear icon and navigate to the **Integrations** tab.\n3. Find and enable the **Resend** integration.\n4. Paste your **API Key** in the input field.\n5. Click **Connect** to confirm the connection.\n","packages/integrations-docs/src/integrations_docs/docs/roboflow.md":"---\ntags: AI\ndescription: Connect your apps to Roboflow to use computer vision models and datasets for image detection, classification, and segmentation.\n---\n# Roboflow Integration\n\nThe **Roboflow Integration** allows your app to use [Roboflow](https://roboflow.com/) to run and deploy computer vision models without complex infrastructure. Once connected, you can use Roboflow to power image detection, object tracking, classification, and segmentation workflows.\n\n## What You Can Do\n\nWith Roboflow, your app can:\n- Run **pre-trained computer vision models** for detection, classification, or segmentation.  \n- Deploy and use **custom-trained models** built in Roboflow.  \n- Automate workflows that rely on visual inputs — e.g., quality checks, object detection, image analysis.  \n- Ingest and process **images in real time**.  \n- Combine vision outputs with other integrations (e.g., AI reasoning, automation flows).\n\n```md alert\n## This integration currently supports image inputs only.\nVideo and streaming inputs are not yet supported.\n```\n\n## Step 1: Obtain a Roboflow API Key\n\n1. Go to your [Roboflow Account](https://roboflow.com/).\n2. Navigate to **Settings → API Keys**.  \n3. Copy your Private API Key.\n\n\n## Step 2: Set up your Model in Roboflow\n\n1. Go to Workflows and create a new workflow.\n2. Set up the workflow you want to use in your app, ensuring that it takes an image as input.\n3. Click the `deploy` button, select `Images` and then select `Integrate with my app or website`.\n4. Copy the `workspace_name` and `workflow_id` from the provided code snippet.\n\n![Roboflow](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/roboflow.webp)\n\n## Step 3: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Roboflow** in your app settings.  \n2. Paste your **Roboflow API Key**, **Workspace Name**, and **Workflow ID** in the input fields.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can call Roboflow models directly from workflows, UI actions, or automated triggers.\n\n\n## Step 4: Notes\n\n* **Keep your key secure:** Never expose your Roboflow key in client-side code.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys to control access.  \n* **Model flexibility:** Use community models or your own custom-trained models.  \n* **Real-time vision:** Ideal for applications involving cameras, inspection, monitoring, or visual AI.\n","packages/integrations-docs/src/integrations_docs/docs/snowflake.md":"# Snowflake\n\nSnowflake is a cloud-based data warehousing platform that enables users to store, manage, and analyze large volumes of data. It provides a scalable and flexible architecture that separates storage and compute resources, allowing for efficient data processing and querying.\n\nThe integration supports two authentication methods: **OAuth** (each user logs in with their own Snowflake account) and **Key Pair** (the app authenticates as a shared service user with an RSA key pair — no browser login, tokens never expire mid-session).\n\n## OAuth\n\n### Step 1: Create an OAuth Integration in Snowflake\n\nTo enable OAuth for your Snowflake account, an administrator must first register the connected app.\n\n```python exec\nimport reflex as rx\nfrom flexgen.ui.components.markdown import get_base_component_map\n\ntry:\n    from flexgen.integrations.snowflake import SnowflakeAuthState\nexcept ImportError:\n    redirect_uri = (\n        \"https://build.reflex.dev/_reflex_oidc_snowflake/authorization-code/callback\"\n    )\nelse:\n    redirect_uri = SnowflakeAuthState.redirect_uri\n```\n\n```python eval\n# Actually render the real redirect_uri for copy/paste\nget_base_component_map()[\"pre\"](\n    f\"\"\"CREATE SECURITY INTEGRATION oauth_reflex_build_int\n  TYPE = OAUTH\n  ENABLED = TRUE\n  OAUTH_CLIENT = CUSTOM\n  OAUTH_CLIENT_TYPE = 'PUBLIC'\n  OAUTH_REDIRECT_URI = '{redirect_uri}'\n  OAUTH_ISSUE_REFRESH_TOKENS = TRUE\n  OAUTH_REFRESH_TOKEN_VALIDITY = 86400;\"\"\",\n    language=\"sql\",\n)\n```\n\n### Step 2: Log in via OAuth\n\nNOTE: you must use a non-admin account to complete the OAuth flow.\n\n## Key Pair\n\nKey-pair authentication connects as a Snowflake service user with a registered RSA public key. Use it when the app should have its own identity instead of a user's OAuth session.\n\n### Step 1: Generate an RSA key pair\n\nGenerate an unencrypted PKCS#8 private key:\n\n```bash\nopenssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt\n```\n\nOr generate an encrypted one, if your organization requires passphrase-protected keys at rest:\n\n```bash\nopenssl genrsa 2048 | openssl pkcs8 -topk8 -v2 aes256 -inform PEM -out rsa_key.p8\n```\n\nThen derive the public key:\n\n```bash\nopenssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub\n```\n\n### Step 2: Register the public key on a Snowflake user\n\nRun as an administrator, pasting the contents of `rsa_key.pub` without the `BEGIN/END PUBLIC KEY` lines:\n\n```sql\nCREATE USER IF NOT EXISTS svc_reflex TYPE = SERVICE DEFAULT_ROLE = <role>;\nGRANT ROLE <role> TO USER svc_reflex;\n\nALTER USER svc_reflex SET RSA_PUBLIC_KEY='MIIBIjANBgkq...';\n```\n\nTo print the `ALTER USER` statement with the key already formatted on a single line:\n\n```bash\necho \"ALTER USER svc_reflex SET RSA_PUBLIC_KEY='$(grep -v '^-----' rsa_key.pub | tr -d '\\n')';\"\n```\n\nThe `GRANT ROLE` is required — `DEFAULT_ROLE` only sets a preference and does not grant the role. The role needs `USAGE` on the warehouse, database, and schema the app will query. To verify the registration, compare `RSA_PUBLIC_KEY_FP` from `DESC USER svc_reflex` (Snowflake prefixes it with `SHA256:`) against the output of:\n\n```bash\nopenssl rsa -pubin -in rsa_key.pub -outform DER | openssl dgst -sha256 -binary | openssl enc -base64\n```\n\n### Step 3: Fill in the Key Pair tab\n\n- `SNOWFLAKE_USER`: the user the public key is registered on (e.g. `svc_reflex`)\n- `SNOWFLAKE_PRIVATE_KEY`: paste the full contents of `rsa_key.p8` (mangled newlines from copy/paste are fine)\n- `SNOWFLAKE_PRIVATE_KEY_PASSPHRASE`: only if the private key is encrypted. It is stored with the integration secrets and used to decrypt the key at connect time. To strip a passphrase from an existing key instead: `openssl pkcs8 -topk8 -in rsa_key.p8 -nocrypt -out rsa_key_plain.p8`\n\nThe warehouse and database dropdowns populate once the key pair authenticates, which doubles as a connection check.\n\nIf a private key is ever lost or leaked, generate a new pair and re-run the `ALTER USER ... SET RSA_PUBLIC_KEY` — Snowflake also supports `RSA_PUBLIC_KEY_2` for zero-downtime rotation.\n\n# Roadmap \n\nIn the future, this integration will be extended to support external OAuth\nflows, service principal authentication, and external network access.\n","packages/integrations-docs/src/integrations_docs/docs/stripe.md":"---\ndescription: Connect your apps to Stripe to accept payments, manage subscriptions, and handle billing securely.\n---\n# Stripe Integration\n\nThe **Stripe Integration** allows your app to use [Stripe](https://stripe.com/) to power secure payments, subscriptions, and billing workflows. Once connected, you can process transactions, manage customers, and trigger payment flows directly from your app.\n\n## What You Can Do\n\nWith Stripe, your app can:\n- **Accept one-time payments** or set up **recurring subscriptions**.  \n- **Manage customers**, payment methods, and invoices.  \n- Handle **refunds, payment confirmations**, and notifications.  \n- Automate billing flows and webhook-based actions.  \n- Build secure, PCI-compliant checkout experiences with ease.\n\n## Step 1: Obtain a Stripe API Key\n\n1. Go to your [Stripe Dashboard](https://dashboard.stripe.com/).  \n2. Navigate to **Developers → API Keys**.  \n3. Copy your **Secret Key** (or create a restricted key for added security).\n\n   * **Example:** `sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n> 💡 Use test keys in development environments and live keys in production.\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Stripe** in your app settings.  \n2. Paste your **Stripe API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can process payments and manage billing directly from workflows and UI actions.\n\n## Step 3: Notes\n\n* **Keep your API key secure:** Never expose your Stripe key in client-side code.  \n* **Use environment-specific keys:** Test keys for staging, live keys for production.  \n* **Secure transactions:** All payment processing is handled through Stripe’s PCI-compliant infrastructure.  \n","packages/integrations-docs/src/integrations_docs/docs/supabase.md":"---\ntags: Data Infrastructure\ndescription: Connect your apps to Supabase to use a hosted Postgres database with real-time capabilities and powerful APIs.\n---\n# Supabase Integration\n\nThe **Supabase Integration** allows your app to connect to [Supabase](https://supabase.com/) — a hosted Postgres database with real-time subscriptions, authentication, and file storage. Once connected, your app can query and update data securely, power dashboards, and sync workflows in real time.\n\n## What You Can Do\n\nWith Supabase, your app can:\n- **Read and write data** using Postgres through a simple REST or client API.  \n- Enable **real-time updates** that sync automatically to your UI.  \n- Use **row-level security** and access control for safe data management.  \n- Store and retrieve files with Supabase Storage.  \n- Integrate seamlessly with AI, dashboards, or internal tools.\n\n## Step 1: Obtain Your Supabase URL and Key\n\n1. Go to your [Supabase Project](https://supabase.com/).\n2. Choose the project you want to connect.\n3. Navigate to **Project Settings**.\n4. Go to **Data API** and copy your `Supabase_URL`.\n5. Then go to **API Keys** and copy your `Supabase_Key` (the secret key).\n\n   * **Example URL:** `https://your-project.supabase.co`  \n   * **Example Key:** `sb_xxxxxxxxxxxxxxxxxxxxxxxxxxxx.`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Supabase** in your app settings.  \n2. Paste your **Supabase URL** and **Supabase Key** into the fields.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can query and update your Supabase database directly from workflows and UI actions.\n\n## Step 3: Notes\n\n* **Keep your keys secure:** Never expose the `Supabase_Key` key in client-side code.  \n* **Use environment-specific keys:** Separate dev, staging, and production projects for clean access control.  \n* **Realtime support:** Supabase enables live syncing of data changes.  \n* **Row-level security:** Make sure to configure policies appropriately for your use case.\n","packages/integrations-docs/src/integrations_docs/docs/twilio.md":"---\ntags: Communication\ndescription: Connect your apps to Twilio to send SMS, WhatsApp messages, and voice calls programmatically.\n---\n# Twilio Integration\n\nThe **Twilio Integration** allows your app to use [Twilio](https://www.twilio.com/) to send and receive SMS, WhatsApp messages, and voice calls. Once connected, your app can trigger messages or calls directly from workflows, user actions, or automated events.\n\n## What You Can Do\n\nWith Twilio, your app can:\n- **Send SMS** messages to users or customers globally.  \n- **Send and receive WhatsApp messages**.  \n- **Make and manage voice calls** programmatically.  \n- Automate **notifications**, **alerts**, and **transactional messages**.  \n- Integrate messaging into AI workflows for dynamic, real-time communication.\n\n## Step 1: Obtain Twilio Credentials\n\n1. Go to your [Twilio Console](https://www.twilio.com/console).  \n2. Copy your **Account SID** and **Auth Token** from the dashboard.  \n\n   * **Example Account SID:** `ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`  \n   * **Example Auth Token:** `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Twilio** in your app settings.  \n2. Paste your **Account SID** and **Auth Token** in the input fields.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can send messages or make calls through Twilio directly in workflows and components.\n\n## Step 3: Notes\n\n* **Keep your credentials secure:** Never expose your Auth Token in client-side code.  \n* **Use environment-specific credentials:** Separate dev, staging, and production credentials.  \n* **Phone number setup:** Ensure you’ve configured a valid Twilio number for sending messages or calls.  \n* **Regulatory compliance:** Review Twilio’s messaging and voice compliance requirements for your region.\n","packages/reflex-base/README.md":"# reflex-base\n\nCore types for the Reflex framework.\n","packages/reflex-bench/README.md":"# reflex-bench\n\nMacro benchmarks for Reflex. `reflex-bench` drives benchmarks through one command\nline interface, stores every raw sample with the machine it ran on, and compares\nresults with statistics that say \"inconclusive\" instead of guessing.\n\nThe CLI is the only code path: CI runs the same commands and only adds output\ntargets. The harness never imports the reflex under test; benchmarks reach it\nthrough subprocesses, HTTP, sockets and a browser. This package is used inside\nthis repository only and is never published.\n\n```console\n$ uv run reflex-bench list --suite selftest\n$ uv run reflex-bench run --suite selftest\n$ uv run reflex-bench run selftest.noise --param shift=1.2 --baseline 0001\n$ uv run reflex-bench run --reflex 0.8.23 --suite selftest\n$ uv run reflex-bench ab --base git:main --head workspace --suite selftest\n$ uv run reflex-bench compare base.json head.json --format md\n$ uv run reflex-bench doctor\n$ uv run reflex-bench export result.json --to bmf\n$ uv run reflex-bench budgets check result.json\n$ uv run reflex-bench noise ../bench-data/runs/<profile_id> --format md\n$ uv run reflex-bench subjects list\n```\n\n## Commands\n\n| Command | What it does |\n| --- | --- |\n| `list [FILTER...] [--suite NAME]` | Benchmarks with their parameters, kind, metrics, suites and estimated duration. |\n| `run [FILTER...] [--reflex SPEC]` | Runs benchmarks against one reflex, prints the result table, autosaves the result and optionally compares it with a baseline. |\n| `ab --base SPEC --head SPEC [FILTER...]` | Measures two reflexes in alternation on this machine and compares them ([A/B runs](#ab-runs)). |\n| `show FILE [--samples]` | One result in detail, optionally with every raw sample. |\n| `compare BASE HEAD [--format term\\|md\\|json]` | Compares two results; `json` prints the annotated head result. |\n| `doctor` | Machine checks that affect measurement noise, with fix hints. |\n| `export FILE --to md\\|bmf [-o OUT]` | Pull request markdown or [Bencher Metric Format](https://bencher.dev/docs/reference/bencher-metric-format/). |\n| `budgets check FILE [--budgets BUDGETS]` | Checks a result against the metric maxima of `budgets.json` ([Size budgets](#size-budgets)). |\n| `noise PATH... [--kind daily] [--min-runs 10] [--format term\\|md\\|json]` | The per-metric noise table of stored results ([Noise table](#noise-table)). |\n| `subjects list` | The cached [subject](#subjects) venvs: spec, Python, key, size and last use. |\n| `subjects prune [--older-than 30d]` | Deletes venvs not used for that long (`30d`, `12h`, `90m`), leftovers of interrupted builds and git worktrees no venv uses. |\n\n`FILTER` is a glob on the benchmark id (`lifecycle.*`, `*.warm`). Suites are named\nselections: `smoke`, `pr`, `daily`, `macro` (the timings the CodSpeed macro\nrunner measures, see [CI](#ci)), `selftest` and `all` (every benchmark except\nthe self-tests). Self-tests only run when asked for, with `--suite selftest` or a\nfilter starting with `selftest`.\n\nMain `run` options (every effective value is printed in the header and stored in\nthe result's `policy` block):\n\n| Option | Default | |\n| --- | --- | --- |\n| `--reflex SPEC` | `workspace` | The reflex to measure (see [Subjects](#subjects)). |\n| `--python VERSION` | the harness's | The Python of subject venvs (major.minor of the interpreter running reflex-bench, which the workspace runs on). |\n| `--runs N` | automatic | Fixed number of timed runs. |\n| `--min-runs`, `--max-runs`, `--min-time` | 10, max(30, min-runs), 30 s | The automatic run count (below). |\n| `--warmup N` | per benchmark | Untimed runs, stored but excluded from statistics. |\n| `--timeout SECONDS` | per benchmark | Deadline of each `prepare`, `sample` and `conclude` call. |\n| `--param KEY=VALUE` | | Restricts a parameter to one value, or sets a new value or a hidden parameter. |\n| `--baseline NAME\\|FILE\\|NUMBER` | | Compares with a file, a named baseline or an autosave number (`0041`). |\n| `--save/--no-save`, `--save-as NAME`, `--json FILE` | autosave | Where to store the result. |\n| `--threshold PCT`, `--alpha FLOAT` | 3, 0.01 | Practical threshold and significance level of verdicts. |\n| `--fail-on regression\\|never`, `--fail-on-inconclusive` | never locally, regression when `CI=true` | Exit codes 2 and 3. |\n| `--smoke` | | One run, no warmup, no statistics: checks that each benchmark works. |\n| `--ndjson` | | Progress events as JSON lines on stdout; human output moves to stderr. |\n| `--seed INT` | random | Seeds each benchmark's RNG and the bootstrap; always recorded. |\n| `--keep` | | Keeps each benchmark's work directory. |\n| `--kind` | `local` or `ci` | The run kind recorded in the result (`pr`, `daily`, `backfill`, `aa`). |\n\nExit codes: `0` ok, `1` harness error (including usage errors and every benchmark\nfailing), `2` regression with `--fail-on regression`, `3` inconclusive result\nwith `--fail-on-inconclusive`, `4` nothing to compare (no metric has samples on\nboth sides with matching series keys, and no benchmark started failing). A\nbenchmark that fails or times out is reported with its status and does not stop\nthe run; when comparing, one that fails or times out in head but not in base (or\nis new) is a regression.\nCtrl-C during `run` exits with `130` after saving the benchmarks that finished,\nmarked with `\"interrupted\": true`; the benchmark in progress is left out, and `--save-as` keeps the old baseline.\n\nWith `CI=true` the output is plain (no colors, no live progress, one line per\nfinished benchmark) and `--fail-on` defaults to `regression`. Nothing else changes.\n\n## Subjects\n\nThe reflex under test, `--reflex SPEC` (`--base` and `--head` for `ab`):\n\n| SPEC | Meaning |\n| --- | --- |\n| `workspace` (default) | This checkout, in the harness's own environment. |\n| `0.8.23`, any PEP 440 version | `reflex==<version>` from PyPI. |\n| `git:<ref>` | A commit, branch or tag of the current repository, e.g. `git:main`, `git:v0.9.11`. |\n| `path:<dir>` | Another local checkout, e.g. `path:../reflex-wt-other`. |\n\nEvery spec but `workspace` runs in its own virtualenv, `<home>/venvs/<key>/`,\ncreated with `uv venv --relocatable --python <--python>` and never containing\nthe harness. The key is the first 16 hex digits of the SHA-256 of the subject's\nidentity (the version; the commit of a git ref; the absolute path, commit and\ndirty flag of a path), the `--python` value and the harness's extra subject\nrequirements (`SUBJECT_REQUIREMENTS`: `sqlmodel` and `alembic`, the ranges of reflex's `db` extra, for the playground's database, and `plotly`, which `rx.plotly` imports). A venv is built in a temporary directory and renamed\ninto place when complete, under a lock, so a half-built venv is never reused and\nconcurrent runs build it once. A `path:` subject with uncommitted changes (or\noutside git) is rebuilt every time. The build happens before anything is timed\nand says what it does (`building venv for reflex 0.8.23 (py3.12)…`, `reusing\nvenv …`).\n\nA `git:` subject is checked out as a detached git worktree in\n`<home>/src/<commit>/` (reused when present; a worktree keeps the tags the\npackages' versions are computed from). A checkout with a `uv.lock` is installed\nwith the dependency set of `uv export --frozen --no-dev --package reflex`,\nwhich lists `reflex` and every workspace package it needs (`reflex-base`,\n`reflex-components-*`, ...) as editable paths in the checkout, so the\ndevelopment versions reflex pins never come from PyPI; the other dependencies\nare the locked ones, and the exported list is kept in the venv as\n`reflex-bench-requirements.txt`. A checkout without a lock (older than uv) is\ninstalled directly, editable.\n\nThe subject records its interpreter, `reflex_version`, `python_version` and\n`extra.granian`, all read by running the subject's interpreter on package\nmetadata (the harness never imports reflex), plus `commit` and `dirty` for git\nand path subjects. Benchmarks get the subject's interpreter directory first on\n`PATH` in `ctx.env`, so commands reflex starts by name (reflex 0.8 starts\n`granian` in production mode) come from the subject's venv.\n`subjects list` and `subjects prune` manage the cached venvs.\n\n## Writing a benchmark\n\nBenchmarks live in modules of `reflex_bench.suites`; every module there is\nimported on discovery.\n\n```python\nimport time\n\nfrom reflex_bench.registry import Metric, benchmark\n\n\n@benchmark(\n    id=\"selftest.sleep\",\n    suites=(\"selftest\",),\n    kind=\"time\",  # time | startup | rate | latency | peakmem | track\n    params={\"ms\": [10, 50]},  # cartesian product: selftest.sleep[ms=10], [ms=50]\n    metrics={\"wall\": Metric(unit=\"s\", direction=\"lower\")},\n    warmup=1,\n    timeout=60,  # seconds per prepare/sample/conclude call\n    estimate=5,  # rough seconds per sample, for `list`\n    min_version=None,  # e.g. \"0.9.8\": older subjects report \"unsupported\"\n)\nclass Sleep:\n    \"\"\"Sleep for a fixed time; checks the timing pipeline.\"\"\"\n\n    def setup_cache(self, ctx): ...  # once per subject and parameter set\n    def setup(self, ctx): ...  # once per instance\n    def prepare(self, ctx): ...  # before each sample, untimed\n    def sample(self, ctx):  # one sample\n        time.sleep(ctx.params[\"ms\"] / 1000)\n\n    def conclude(self, ctx): ...  # after each sample, untimed\n    def cleanup(self, ctx): ...  # once at the end\n```\n\nEvery hook except `sample` is optional; `conclude` and `cleanup` always run, also\nafter a failure or a timeout. Further `@benchmark` arguments:\n`hidden_params={\"name\": default}` for parameters that are passed to hooks but are\nnot part of the name or the series key, `suite_params={\"smoke\": {\"sessions\":\n[10]}}` for the values a parameter takes when that suite is selected (a quick\nsubset of the grid; `--param` still wins), and `setup_timeout` (600 s) for\n`setup_cache`, `setup` and `cleanup`.\n\n**Metrics** are declared with `Metric(unit, direction, assume=\"nothing\",\ndescription=\"\")`. Values are stored in SI base units (`s`, `B`, `ev/s`, `1` for\ncounts); scaling to ms or MB only happens on display. `assume=\"exact\"` marks a\ndeterministic value: one run is enough and any variance is reported.\n\n**`sample(ctx)`** returns `None`, a dict of metric values, or\n`SampleResult(values, extra)` whose JSON-serializable `extra` is stored with the\nsample. The harness always times the call; a declared `wall` metric that\n`sample()` does not return is filled with that duration. Returning an undeclared\nmetric, or leaving out a declared one, fails the benchmark.\n\n**`ctx`** is a `reflex_bench.context.Context`: `subject` (the reflex under test:\n`python`, `reflex_version`, `commit`, `dirty`, ...), `params` (hidden ones\nincluded), `workdir` (fresh per instance, removed after `cleanup` unless\n`--keep`), `cache_dir` (persistent per subject commit, benchmark id and\nparameter set, for `setup_cache` results; the hook decides what to reuse),\n`env` (the environment for subprocesses: telemetry and update checks off,\n`NO_COLOR`, `PYTHONUNBUFFERED`, `PYTHONHASHSEED=0`, granian, the subject's\ninterpreter directory first on `PATH`), `rng` (seeded), `log`, `arm` and\n`dims`: `setup` may name how the values are measured there, e.g.\n`ctx.dims[\"memory_method\"] = \"cgroup\"`, and the scheduler copies it into the\nentry's `dims`, which are part of the series key, so differently measured\nvalues never pair up in a comparison.\n\nAll hooks of an instance run on one worker thread, so thread-bound resources\n(such as a sync Playwright browser) work across hooks. A hook that misses its\ndeadline ends the instance with status `timeout`; the stuck thread is abandoned\nand the remaining teardown hooks run on a fresh one (as they do after Ctrl-C),\nso `conclude` should kill whatever `sample` started. A hook still running a few\nseconds after teardown keeps the work directory and skips the benchmark's\nremaining parameter sets. `reflex_bench.registry.Instance` exposes the hooks as\nzero-argument methods and `reflex_bench.scheduler.make_context` builds the same\ncontext as the scheduler, for callers other than the scheduler.\n\n**Keep heavy processes per sample.** During [`ab`](#ab-runs) both arms'\nsessions are open at the same time, `setup` to `cleanup`. A benchmark that\nkeeps a heavy process (a server) alive between samples runs two of them at\nonce, which distorts both arms. Start per-sample processes in `prepare` or\n`sample` and stop them in `conclude`. This is not enforced. Two kinds of\nbenchmarks keep one server per instance on purpose, and say why in their\ndocstrings: `browser.prod.pageload` (a prod start includes a full frontend\nbuild, and an idle second server does not touch page load) and the `hmr.*`\nbenchmarks (a dev start plus hydration before every edit would multiply their\nrun time by about ten, and the other arm's server only idles while this one\nrecompiles).\n\n## Driving reflex\n\nBenchmarks start the reflex under test as a user does, `<python> -m reflex ...`\nwith the subject's interpreter, through `reflex_bench.drivers.app_process`:\n\n```python\nfrom reflex_bench.collectors.cgroup import CgroupScope\nfrom reflex_bench.drivers.app_process import AppProcess, cache_env, run_cli\n\nenv = {**ctx.env, **cache_env(reflex_dir=ctx.cache_dir / \"reflex\")}\nscope = CgroupScope() if CgroupScope.available() is None else None\nresult = run_cli(\n    ctx.subject.python,\n    [\"compile\"],\n    cwd=app,\n    env=env,\n    timeout=600,\n    scope=scope,\n    phases=True,\n    sample_memory=scope is None,\n).check()  # wall_s, cpu_s, peak_mem_bytes, timing, attribution()\n\nself.app = AppProcess(\n    ctx.subject.python,\n    app,\n    mode=\"prod\",\n    reflex_version=ctx.subject.reflex_version,\n    env=env,\n)\nreadiness = self.app.start()  # process-ready: ready lines + every port accepts TCP\nself.app.wait_http_ready()  # GET / (or /ping without a frontend) answers 200\n# conclude(): self.app.stop() kills the whole process tree\n```\n\nThe driver picks free ports, expects the ready lines of the subject's version\nand mode (0.8.23 prod runs sirv and the backend on two ports, 0.9 prod one\nport) and never trusts a line without a TCP probe. It runs with the `env` it\nis given: pass `ctx.env`, or `reflex_bench.context.subject_env(python)` outside\na benchmark, so the subject's commands come first on `PATH`. Each command runs in its own session; `stop()` and the end of\n`run_cli` kill the whole tree, children that started their own session\nincluded. Peak memory and CPU come from a transient cgroup v2 scope when\n`systemd-run` works (user manager, or sudo on CI), else from PSS sampling\n(`memory_method: pss_sampling`, never compared with cgroup peaks);\n`reflex-bench doctor` shows which. With `phases=True`, `attribution()` splits\nthe command's wall and CPU time between three classes of processes sampled\nfrom its tree: `install` (`bun`/`npm`/`pnpm`/`yarn` `install`/`add` and what\nthey start), `frontend` (`node`, `vite`, `react-router`, `esbuild` and what\nthey start) and `python`, the interpreter and everything else. A tool's wall\nis the time it was alive; python's is the total minus the time any tool was\nalive, when the interpreter only waits. `cpu` per class is checked against\nthe measured total (`mismatch` beyond 10 %), `idle` is wall time not spent on\nCPU, and `python_breakdown` keeps the `[timing]` phases of the compile.\n`selftest.app.compile` and `selftest.app.dev_ready` exercise all of it against\na blank app.\n`run_cli(..., prefix=(\"-c\", \"import reflex\"))` runs other interpreter\narguments than `-m reflex` through the same process tree code.\n\n## Fixtures\n\nA fixture is the app a benchmark drives, described by a `FixtureDoc` (`name`,\n`content_hash`, `params`). A benchmark sets `ctx.fixture` in `setup_cache` or\n`setup`, and its entry records the name in `dims` (`{\"fixture\": \"playground\"}`,\npart of the pairing and series keys) and the hash in `fixture_hash` (part of\nthe series key only): an edited fixture pairs with its old self and `compare`\nreports the pair as not comparable, `fixture content hash differs`, unless\n`--force`. Hooks record anything else that separates series in `ctx.dims`.\nOne invocation drives several fixtures, so the document-level `fixture` stays\n`null`.\n\n- **The playground**, `examples/playground`: a committed app whose hash is the\n  line in its `.content-hash` (see its README for the element ids and hot reload\n  targets benchmarks rely on). `materialize_playground(dest)` copies it without\n  build output. It has 21 pages (about 3000 component instances, 16 states)\n  and a sqlite table: loading the app seeds 2000 fixed rows into an empty table,\n  in one transaction, so each staged copy creates its `playground.db` once. It\n  needs `sqlmodel`, `alembic` and `plotly`, which\n  `SUBJECT_REQUIREMENTS` installs into subject venvs; the workspace gets them\n  from the `dev` group.\n- **Generated apps**, `reflex_bench.fixtures.generate`: `GenParams(pages,\n  components_per_page, state_vars, substate_depth, computed_vars, seed)` gives a\n  deterministic app of any size, hashed from the generator's source and the\n  parameters. Its hot reload targets follow the playground's pragma form and\n  are listed in `bench-manifest.json`. `uv run python -m\n  reflex_bench.fixtures.generate --pages 10 DEST` writes one to look at.\n\n`ensure_fixture(ctx.cache_dir, describe, make)` keeps the app in\n`cache_dir/app` with a `fixture.json` stamp, and rebuilds it when the stamp no\nlonger matches: `setup_cache` directories are keyed by subject and parameters,\nnot by the app. `bump_marker(path, target, n)` sets a hot reload target's\nstring to `m-<n>-<target>`; the benchmark restores the module in `conclude`, so\nthe cached app stays the fixture its stamp describes.\n\nThe `lifecycle.*` benchmarks (`reflex_bench/suites/lifecycle.py`) time `init`,\n`compile`, `export`, `run` until HTTP-ready and `import reflex as rx; rx.App;\nrx.State` (the import alone is lazy), each in a cache state its id names\n(`cold`, `warm`, `incremental`); the module docstring lists which caches each\none starts from. No sample downloads anything: a subject downloads bun once,\ninto its shared `REFLEX_DIR` (`ctx.subject_cache_dir/reflex`), and installs the\nplayground's packages once, into its shared bun cache\n(`ctx.subject_cache_dir/bun-cache`); a cold state is a fresh directory that\nthese primed copies fill (`init.cold` gets a copy of bun, `compile.cold` a fresh\napp copy with the primed lockfile that links its packages from the cache), so a\nsample measures reflex and bun, not the network. Each `time` benchmark chooses its collector once, in\n`setup`, and records it in `dims` (`collector: cgroup | fallback`), so cgroup\npeaks and PSS peaks never share a series.\n\n## Fixture apps\n\nThe browser and hot reload benchmarks drive `examples/playground` (see its\nREADME for the element ids and `# bench:hmr-target` pragmas they rely on). The\nharness reads it from the checkout it runs in, never from the subject's\nenvironment, so `reflex-bench` must run from a reflex checkout.\n`reflex_bench.fixtures.prime(ctx)` copies it into the instance's cache directory\n(`<cache>/app/<arm>`: in an A/A run both arms share a cache directory, and two\nservers must not run in one app), without build output, and compiles it once\n(bun and the frontend packages), so the benchmarks' own starts are warm. The\nstaged copy is what the hot reload benchmarks edit; the checkout never changes.\nEvery sample records the playground's `.content-hash` in\n`extra[\"fixture_hash\"]`. `reflex_bench.fixtures.FIXTURES` maps the `app`\nparameter of the hot reload benchmarks to a staging function; `playground` is\nthe only one so far.\n\n## Event benchmarks\n\n`reflex_bench.suites.events` measures how many events the playground\n(`examples/playground`) answers and how fast. Each benchmark instance starts it\nonce as a production backend (`reflex run --env prod --backend-only`, one\ngranian worker), and each sample drives it for a few seconds with\n`reflex_bench.drivers.events`, a socket.io load generator that speaks reflex's\nevent websocket over `websockets` (no python-socketio). Sessions are browser\ntabs: each connects with its own token, hydrates like a page load, then sends\n`BenchState.set_seq*` events whose delta echoes a sequence number.\n\nThe grid holds the common points, about 30 minutes with the default policy.\nReflex's default state manager is disk, or redis with a `redis_url`, so every\nbenchmark runs on `disk` (and on `redis` when `REFLEX_REDIS_URL` is set), at 10\nsessions except `at_1hz` (200 sessions) and the fan-out (25 linked sessions).\nOnly `simple` also runs on `memory`, the framework's cost without state I/O,\nand at 50 sessions. Other sizes run by name with `--param`, e.g.\n`reflex-bench run 'events.complex.capacity' --param sessions=200`.\n\nCI minutes are scarce, so `smoke` runs two points, about 2 minutes per reflex\nwith the default policy: `events.simple.capacity[manager=disk,sessions=10]`\nand `events.simple.latency[manager=disk,sessions=10,rate=500]`. `daily` adds\nthe shared state at the same point,\n`events.shared_contention.capacity[manager=disk,sessions=10]` and\n`events.shared_contention.latency[manager=disk,sessions=10,rate=auto]`, and\n`events.shared_fanout.broadcast[manager=disk,linked=25]`. The other shapes,\nthe knee and `at_1hz` run with `--suite all` or by name.\n\n| Benchmark | Suites | Parameters | Load | Metrics |\n| --- | --- | --- | --- | --- |\n| `events.<shape>.capacity` | `smoke`, `daily` (simple, `manager=disk`, `sessions=10`) | `manager`, `sessions` 10 (simple: 10, 50) | closed loop, 3 s after 1 s | `throughput`, `service_p50`, `cpu_per_event` |\n| `events.<shape>.latency` | `smoke`, `daily` (simple, `manager=disk`, `sessions=10`, `rate=500`) | `manager`, `sessions`, `rate` | open loop, 5 s after 1 s | `response_p50`, `p90`, `p99`, `max`, `throughput`, `unanswered`, `cpu_per_event` |\n| `events.shared_contention.capacity` | `daily` (`manager=disk`, `sessions=10`) | `manager`, `sessions` 10 | the same as `capacity`, every session linked to one `rx.SharedState` board | the same as `capacity` |\n| `events.shared_contention.latency` | `daily` (`manager=disk`, `sessions=10`, `rate=auto`) | `manager`, `sessions`, `rate` | the same as `latency`, every session linked to one board | the same as `latency` |\n| `events.shared_fanout.broadcast` | `daily` (`manager=disk`, `linked=25`) | `manager`, `linked` 25 | one linked session sends, closed loop, 3 s after 1 s; answered once every linked session has the delta | `throughput`, `broadcast_p50`, `broadcast_p99`, `fanout_spread_p50`, `cpu_per_event` |\n| `events.simple.knee` | (`all`) | `manager`, `sessions` 10 | open loop at 10 % to 110 % of the capacity, 4 s after 1 s each | `knee_rate`, `low_load_p99` |\n| `events.sessions.at_1hz` | (`all`) | `manager`, `sessions` 200 | open loop, 1 ev/s per session, 10 s after 3 s | `response_p50`, `response_p99`, `unanswered`, `cpu_per_event` |\n| `selftest.events.calibrate` | `selftest` | | the generator against an echo server: closed loop, then open loop at 1500 ev/s | `closed_ceiling`, `open_lag_p99` |\n\n- **Shapes**: `simple` (`set_seq`), `complex` (three vars behind a chain of\n  three computed vars), `cross` (`get_state` of another state), `background` (a\n  background task). Background tasks may finish in any order, so for\n  `background` an answer that overtakes an earlier event counts as\n  `out_of_order` without making that event unanswered. `shared_contention`\n  (`BoardState.set_seq_shared`) links every session to one board, so each\n  event is fanned out to all the others.\n- **`manager`**: `memory` and `disk`, plus `redis` when `REFLEX_REDIS_URL` is set\n  in the harness's environment when the suite is imported. The URL reaches only\n  the redis instances: reflex uses redis whenever a URL is configured.\n- **`rate`**: `auto` offers half the capacity that a 2 s closed-loop probe\n  measures once per instance, so each arm of an `ab` run is loaded to the same\n  share of its own capacity; `--param rate=N` offers `N` events per second to\n  both, which compares the same absolute load. `smoke` and `daily` offer 500,\n  the same load from one day to the next.\n- **One backend per instance**: it starts in `setup`, which also warms it with\n  the probe, and stops in `cleanup`, so its samples share one warm server; in\n  an `ab` run both arms' backends are up, one idle while the other is measured.\n- **Open and closed loop**: the open loop sends on a fixed schedule whatever\n  the server does and times each answer from the *planned* send time, so a\n  stall counts in every event it delays (no coordinated omission); events\n  without an answer count as `unanswered`, never dropped. The closed loop sends\n  the next event when the previous one is answered: it measures capacity and\n  service time (answer minus actual send), never user latency.\n- **Rates count the window only**: `throughput` (`answered_rate`) is the\n  answers that arrived within the measured window divided by its length, the\n  same as `answered_per_second` summed. The drain after the window only decides\n  which events are `unanswered`; the answers it collects still count in the\n  response percentiles.\n- **Per run, not pooled**: every sample's percentiles come from that run's\n  events; `response_p99` of a run with fewer than 10 000 answered events is kept\n  with `p99_underpowered` in its extra data. Each sample's extra data also holds\n  a 120-bucket log histogram (10 μs to 100 s) for pooled percentiles on display.\n- **CPU per event** is the server tree's CPU time in the measured window divided\n  by the answered events: from its cgroup scope (`cpu_method: cgroup`) or,\n  without one, summed over its processes with psutil (`cpu_method: psutil`),\n  including the children they reaped, so a worker that exits in the window\n  still counts. A CPU time that goes back fails the sample.\n- **Pinning**: on Linux with four CPUs or more, the server runs on the lower\n  half of the physical cores (CPU 0 excluded) and the generator on the upper\n  half, so no core is shared between them through SMT (the kernel's\n  `thread_siblings_list`; without it every CPU counts as a core), with up to 4\n  generator processes (1 up to 10 sessions); `pinning` in the extra data\n  records the split.\n- **Self-check**: a load fails it when a generator process used more than\n  75 % of a core, when the p99 of the send lag (actual minus planned send\n  time) exceeds the larger of 1 ms and 10 % of the median response, or when\n  less than 98 % of the offered events went out in the window. The rules judge\n  the generator alone: a lag tail inflates the response tail by as much,\n  whatever caused it, so the sample fails with `generator saturated` at once\n  and is never taken again. `selftest.events.calibrate` fails the same way\n  when the generator cannot offer 1500 ev/s, three times the highest fixed rate\n  of the suite, against an echo server.\n\nNot parameters yet: injected redis latency, uvicorn instead of granian, and\nmore than one backend worker.\n\n## Memory benchmarks\n\n`reflex_bench.suites.memory` answers how much memory the playground takes,\nwhether it grows, and whether it fits a 512 MiB box. Samples are untimed:\nevery metric is bytes (lower is better) except `passed`. Each sample starts a\nfresh backend (`reflex run --env prod --backend-only`, one granian worker), as\nthe event benchmarks do; `memory.dev.idle` starts the dev server instead.\n\n| Benchmark | Suites | Parameters | One sample | Metrics |\n| --- | --- | --- | --- | --- |\n| `memory.compile.peak` | `daily` | `command` compile, export | `reflex compile` or `reflex export --env prod` of the compiled playground | `peak_mem` |\n| `memory.idle` | `smoke` (memory), `daily` | `manager` | 5 s after `/ping` answers, the median of three PSS reads a second apart | `pss`, `pss_anon`, `pss_file` |\n| `memory.idle.allocator` | (`all`) | `allocator` mimalloc, arena2 | the same with `PYTHONMALLOC=mimalloc` or `MALLOC_ARENA_MAX=2` | the same |\n| `memory.dev.idle` | `daily` | `manager` memory | the same for `reflex run --env dev`, backend and vite dev server, 10 s after the page answers HTTP (no browser, so vite has transformed only what that request needed); the USS of the node, bun and esbuild processes is split from the python ones in the extra data (`backend_uss_bytes`, `frontend_uss_bytes`) | the same |\n| `memory.per_session` | `daily` (`max_sessions=500`) | `manager`, `max_sessions` (1000) | hold 0, 50, 100, 250, 500 and 1000 idle sessions, fit PSS per session; disconnect; wait for the states to expire | `bytes_per_session`, `bytes_per_session_ci_hi`, `residual_after_disconnect`, `residual_after_expiry` |\n| `memory.leak` | `daily` (`events=50000`) | `manager`, `events` (100000) | a closed loop of 10 sessions while the tree's anonymous PSS is sampled | `passed`, `bytes_per_event_ci_hi` |\n| `memory.boot_512mb` | `daily` (memory) | `manager` | compile, then boot and serve, under `MemoryMax=512M` with swap off | `passed`, `peak_compile`, `peak_boot`, `peak_serve` |\n| `memory.boot.min_limit` | (`all`) | `manager` memory | bisects `MemoryMax` from 64 to 1024 MiB in 32 MiB steps over boot and serve | `min_limit` |\n\n- **Methods**: peaks come from a cgroup v2 scope's `memory.peak` where the host\n  can start one (user systemd, or `sudo systemd-run` on CI), else from PSS\n  sampled every 50 ms; steady-state values are the summed PSS of the server's\n  process tree on every host, with the scope's `memory.current`, `anon` and\n  `file` in the extra data when a scope holds the running server (the compile\n  peak reads its scope after the command exited, so it records only whether\n  the peak was reset). `memory_method` in the dims\n  (`cgroup` or `pss_sampling`) names the collector of the values, so cgroup and\n  PSS numbers never share a series. The limit benchmarks need a scope and fail\n  with `cgroup scopes are unavailable: <reason>` without one: nothing else can\n  enforce a limit. `reflex-bench doctor` shows what the host has.\n- **What PSS shows**: the memory the tree holds from the kernel, shared pages\n  split between the processes. CPython and glibc keep freed memory for reuse\n  and rarely hand it back, so a number that does not drop means the process did\n  not shrink, not that something leaks. File-backed pages are also split with\n  processes outside the tree that map the same files (the harness's own\n  interpreter), so `pss_file` moves by a few MB between otherwise identical\n  samples; `pss_anon` is the steadier trend.\n- **Per session**: the sessions connect and hydrate like page loads, then stay\n  idle, held by `reflex_bench.drivers.events.hold_sessions` in a separate\n  process. The server runs with `REFLEX_REDIS_TOKEN_EXPIRATION=<expiry_s>`\n  (hidden; 0, the default, sizes it from the sweep: its settling and reading\n  time, 2 s per hold and a 5 s margin, 23 s for 500 sessions), longer than the\n  sweep: no state manager frees a state when its session disconnects, reflex\n  0.9's memory and disk managers and 0.8's disk manager free it after the\n  expiration, and 0.8's memory manager never does. A sweep that outlasts the\n  expiration fails the sample; a slow host can raise `expiry_s`. The residuals\n  are PSS over the idle baseline. `baseline_bytes_per_session` in the extra\n  data is the same sweep against the in-harness echo server: the floor of a\n  Python `websockets` server, not of python-socketio (the harness does not\n  depend on python-socketio); it is measured once per instance, while the\n  first sample's states expire. The sweep's steps below `max_sessions` are 50,\n  100, 250 and 500, so the slope's t interval has at least three degrees of\n  freedom. The tree's PSS is flat within 0.2 MiB from the moment a hold is\n  ready (against steps of 8 to 47 MiB), so a step settles for 1 s and is read\n  three times 0.5 s apart: about 2.5 s each, and a sample about 40 s.\n- **Leak**: a 5 s closed-loop probe sizes the warmup (`warmup_events`, hidden,\n  5000) and the window (`events`, with 10 % of room); the tree is sampled every\n  hundredth of the window, between 0.1 s and 1 s apart. The x axis is the events\n  answered since the window started (`answered_per_second` of the load), the y\n  axis the anonymous PSS: file-backed pages do not leak. The sample fails with\n  `LeakDetected` when the upper end of the slope's 95 % interval exceeds\n  `tolerance_bytes_per_event` (hidden, 100 B, that is 100 MB per million\n  events) *and* each half of the window grows on its own (the lower end of its\n  slope's interval is above zero): heap warm-up flattens out and one allocator\n  step lifts one half only, a leak grows through both. One 1 MiB arena step in\n  50 000 events is about 30 B per event. An unanswered event or a failed\n  session fails the sample, since the event count would be wrong. `passed` is\n  the gate; the slope itself and the growth over the window are in the extra\n  data (`slope_bytes_per_event`, `growth_bytes`), since near zero they move by\n  hundreds of percent between identical runs. `timeline` in the extra data\n  holds up to 500 `[events, anonymous PSS, USS of the python processes]`\n  points.\n- **512 MiB**: the compile runs in one scope, the server boots and serves 5\n  closed-loop sessions for 5 s in another, each with `MemoryMax=<limit_mb>M`\n  (hidden, 512) and `MemorySwapMax=0`, and each scope is read before its tree\n  stops. A phase that fails, or any `oom` or `oom_kill` in `memory.events`,\n  fails the sample with `MemoryLimitExceeded` naming the phase, the counters,\n  the peak and the log tail. The peak is reset between boot and serve where\n  the kernel can (Linux 6.12 and later; `peak_reset` in the extra data says\n  so), else the serve peak includes the boot. The published 512 MiB number\n  comes from an\n  amd64 reference profile (Fly's `shared-cpu` machines are amd64); arm64 runs\n  are a trend.\n- **Allocators**: `--param allocator=mimalloc|arena2` also works on `memory.idle`,\n  `memory.per_session` and `memory.leak`, and puts the allocator in the dims.\n  mimalloc needs the subject's Python to be 3.13 or later.\n\nNot measured yet: a leak per session (connect/disconnect churn) or per page\nload, redis's `used_memory` per session, and peaks per phase within one command\n(they need `memory.peak` resets, Linux 6.12).\n\n**Finding a leak** (manual; tracemalloc slows the server and inflates its\nmemory, so it never runs in a measured sample). Add a temporary handler to the\napp's state:\n\n```python\n@rx.event\ndef heap_snapshot(self, seq: int):\n    import time, tracemalloc\n\n    tracemalloc.take_snapshot().dump(f\"/tmp/heap-{time.time_ns()}.bin\")\n    self.last_seq = seq\n```\n\nstart the backend with tracemalloc on in every process\n(`PYTHONTRACEMALLOC=25 GRANIAN_WORKERS=1 REFLEX_STATE_MANAGER_MODE=memory\nuv run reflex run --env prod --backend-only --backend-port 8000`), and drive\nit with the generator: a snapshot, a load, another snapshot.\n\n```python\nfrom reflex_bench.drivers.events import EventShape, LoadPlan, run_load, seq_payload\n\nstate = \"reflex___state____state.playground___state____bench_state\"\n\n\ndef load(handler: str, sessions: int, duration_s: float) -> None:\n    shape = EventShape(f\"{state}.{handler}\", seq_payload, state, \"last_seq_rx_state_\")\n    run_load(\n        LoadPlan(\n            backend_url=\"http://localhost:8000\",\n            reflex_version=None,\n            shape=shape,\n            sessions=sessions,\n            mode=\"closed\",\n            rate=None,\n            warmup_s=0,\n            duration_s=duration_s,\n        )\n    )\n\n\nif __name__ == \"__main__\":\n    load(\"heap_snapshot\", 1, 0.001)\n    load(\"set_seq\", 10, 60)\n    load(\"heap_snapshot\", 1, 0.001)\n```\n\nThen compare the two snapshots by line:\n`first, second = map(tracemalloc.Snapshot.load, sorted(glob.glob(\"/tmp/heap-*.bin\")))`\nand print `second.compare_to(first, \"lineno\")[:20]`.\n\n## Wire sizes\n\n`reflex_bench.suites.wire` counts the bytes that cross the event websocket: what\na slow link pays for, which no timing or CPU metric shows. One session connects\nto a fresh production backend per sample (`reflex run --env prod\n--backend-only`, one granian worker, the memory state manager) and sums the\npayload bytes of every frame it sends and receives (a text frame's UTF-8\nlength; the HTTP handshake is not a frame). Sizes are deterministic for a given\napp and reflex version, so every metric is exact and a sample is one run.\n\n| Benchmark | Suites | Parameters | One sample | Metrics |\n| --- | --- | --- | --- | --- |\n| `wire.hydrate` | `pr`, `smoke`, `daily` | | connect and hydrate the playground's index route, until the delta that sets `is_hydrated` | `hydrate_sent_bytes`, `hydrate_received_bytes`, `hydrate_frames` (received) |\n| `wire.event` | `pr`, `smoke` (simple), `daily` | `shape` simple, complex, cross, background | after hydration, one `BenchState.set_seq*` event: the request frame, and every frame received until the delta echoing its sequence number | `request_bytes`, `response_bytes`, `response_frames` |\n| `wire.navigate` | `pr`, `smoke` (item), `daily` | `route` counter (`/counter`), item (`/item/42`, the dynamic `/item/[item_id]` page) | after hydration of `/`, a client-side navigation: the `on_load_internal` frame the frontend's router effect sends from the new route, and every frame received until the delta that sets `is_hydrated` again | `request_bytes`, `response_bytes`, `response_frames` |\n| `wire.delta` | `daily` | `change` set_scalar, append_item, set_one_item, set_dict_key, update_row_field | the same for one small change to a large collection of the generated `wire_delta` app | `response_bytes` |\n\n- **Replies span frames**: `response_bytes` sums every frame from the request\n  until the echo, so 0.8.23's empty update before a background task's delta\n  counts, as does any delta of another state. The extra data keeps the echo\n  frame (`reply`), the largest frame, and `delta_bytes`, the bytes of each\n  substate's part of the deltas re-serialized compactly.\n- **Keepalives do not count**: an engine.io ping and its pong are timing, not\n  payload, so a slow run moves the same bytes as a fast one.\n- **`wire.navigate`** sends what the frontend sends on a route change: one\n  `on_load_internal` with the new route's `router_data`. `update_vars_internal`\n  goes first only once the browser holds a value of a client storage var (the\n  playground's `/storage` page sets some); a fresh browser holds none, on 0.8.23\n  and 0.9 alike, so neither the hydration nor the navigation sends it. The reply carries the root state's `router` and,\n  on the dynamic route, the route argument.\n- **`wire.delta`** does not use the playground: its `setup_cache` writes a\n  small app whose state holds 1000 ints in a list, 1000 keys in a dict and 200\n  dict rows, and compiles it. Every handler also sets `last_seq` (the echo), so\n  the deltas differ only by the collection they carry; `set_scalar` is the\n  control. A whole collection resent for a one-item change shows as\n  `response_bytes` far above the control's.\n- **Dims**: `fixture` names the app (`playground` or `wire_delta`); for\n  `wire.delta`, the entry's `fixture_hash` is the generated source's content\n  hash, so `compare` rejects a pair across a change to the generator.\n\n`AppProcess.t0` is the `time.perf_counter()` taken just before the spawn, the\norigin of every readiness time, and `AppProcess.log_lines()` returns the output\nwith the time each line was read (seconds since `t0`), so other clocks and log\nlines can be put on one timeline.\n\n## Driving a browser\n\n`reflex_bench.drivers.browser` drives headless Chromium through Playwright's\nsync API. Install the browser once:\n\n```console\n$ uv run playwright install --only-shell chromium\n```\n\nHeadless runs launch the headless shell, so the full Chromium is not needed\n(`--only-shell` exists from Playwright 1.49). On a bare CI runner add\n`--with-deps` for the system libraries, and cache `~/.cache/ms-playwright`\nkeyed on the runner's architecture. `reflex-bench doctor` reports whether a\nchromium is installed.\n\n```python\nfrom reflex_bench.drivers.browser import Browser\n\nself.browser = Browser(cpu_throttle=1)  # setup(): one browser per instance\nself.browser.start()  # the calling thread owns it\nresult = self.browser.interactive(self.app, \"/\")  # tier 3, also set in app.readiness\ntab = result.tab  # a page in a fresh context (cold cache); tab.page is Playwright's\ntab.watch(\"edit\", \"text\", \"#bench-marker-leaf\", marker)\nmark = tab.wait_mark(\"edit\", timeout=90)  # {\"perf\": ..., \"epoch\": ...}\n# conclude(): self.browser.close_tab(tab); cleanup(): self.browser.close()\n```\n\nEvery page gets `drivers/bench_page.js` as an init script, which runs before\nany page script in every document, reloaded ones included. The page emits the\n\"done\" signal itself: `tab.watch(id, kind, selector, expected)` has it record a\n*mark* the first time a condition holds (`present`, `text`, `changed`,\n`style:<property>` or `naturalWidth`), checked on every DOM mutation and every\nanimation frame (a computed style or a loaded image is no mutation); a watch,\nand its mark once recorded, survives a reload. `#bench-hydrated` is always watched: `interactive()` waits\nfor it (tier 3: the websocket connected and the first state update applied).\nThe script also collects paint, largest contentful paint, long task and long\nanimation frame entries (`tab.timings()`). `tab.set_alive()` tags the document\nand `tab.alive()` reads the tag back: a full reload loses it. Uncaught page\nerrors fail a sample (`tab.raise_errors()`), console errors and warnings are\ncounted (`tab.drain_console()`, the last error's text in `tab.last_error`), and\nwebsocket payload bytes and HTTP wire bytes (headers included, from the\nDevTools `Network.loadingFinished` events) are summed per page.\n\n**Clocks.** A mark carries `performance.now()` (since navigation start) and\n`Date.now()`. `browser.anchor`, the tightest of three back-to-back reads of\n`time.perf_counter()` and `time.time()` taken at start, maps page time onto\n`perf_counter()`: `anchor.perf_at(epoch) - app.t0` puts a page event on the\napp's timeline within 1 ms (`Date.now()`'s resolution) plus the anchor's\nspread, the harness's own share (well under a microsecond), which is stored\nwith the samples.\n\n**Threads.** The sync API refuses calls from any thread but the one that\nstarted it (`greenlet.error: Cannot switch to a different thread`), and\nteardown hooks run on a fresh thread after a timeout or Ctrl-C. `close()`\ncloses normally on the owner thread and kills from any other; `kill()` never\ntouches Playwright: it SIGKILLs the Playwright driver (the harness's child) and\nthe process group Chromium's root (the driver's child) leads with all its\nhelpers, both found at `start()`, so a hook still blocked in the page gets an\nerror at once. `close_tab()` from another thread kills the\nbrowser too: after a timeout the instance is over. Browsers still open when the\nharness exits are killed. A `Browser` belongs to one instance and arm; during\n`ab` two of them coexist. Playwright is imported on `start()`, which keeps\n`reflex-bench list` about 0.1 s faster.\n\n## Browser benchmarks\n\n| Id | Suites | What one sample measures |\n| --- | --- | --- |\n| `browser.dev.ready` | pr, daily, macro | `reflex run` start to `process_ready` (tier 1), `http_ready` (tier 2) and `interactive_ready` (tier 3), seconds since the spawn; also `nav_to_interactive` (in the page) and `fcp` |\n| `browser.preview.ready` | daily (reflex 0.9.8+) | the same with `--env preview` |\n| `browser.prod.ready` | daily | the same with `--env prod`, frontend build included |\n| `browser.prod.pageload[cpu=1\\|4]` | daily | loading `/` of one prod server in a fresh context (cold cache), CPU throttled 4 times with `cpu=4`, read as soon as the page is interactive: `fcp`, `lcp` (the same paint on the playground), `interactive`, `tbt` (long tasks' time beyond 50 ms before interactive), `ws_bytes`, `transfer_bytes` (wire bytes, headers included; both exact: the same page transfers the same bytes) |\n\nThe `ready` samples store the gaps between the tiers in `extra[\"gaps\"]`. Page\nload metrics are noisy: read the median and its confidence interval over at\nleast 6 runs (outliers are counted, not dropped).\n\n## Hot reload benchmarks\n\nEach `hmr.*` instance starts one app (`reflex run --loglevel debug`) and one\npage, then per sample rewrites the staged app and waits until the page shows\nthe change. The edit's content is built in `prepare`; `sample` writes it to a\nsibling temporary file and moves it over the target, taking `t0` just before\nthat one `os.replace`, and returns as soon as the page's mark is there.\n`latency` is the page's mark minus `t0`, on the wall clock of both. Every edit\nwrites a unique value, so a stale page never satisfies a watch. `conclude`\nwaits until the page has been quiet for 0.5 s (no pending watch, no DOM\nchange), restores the file and waits until the page shows the original and is\nquiet again, which is also the wait between edits. Every hook's waits share\none 90 s deadline. `warmup` is 3 edits.\n\n| Id | Edit | Done when the page shows |\n| --- | --- | --- |\n| `hmr.render.leaf` | the `leaf` pragma literal (index page only) | the new text in `#bench-marker-leaf` |\n| `hmr.render.root` | the `root` pragma literal (every page) | the new text in `#bench-marker-root` |\n| `hmr.handler` | the `handler` pragma literal, set by an event handler | the new value in `#bench-handler-value`; the harness clicks `#bench-handler` every 250 ms (`extra[\"clicks\"]`) |\n| `hmr.css` | the `.bench-hooks` font size in `assets/playground.css` | the computed font size |\n| `hmr.asset` | `assets/mark.svg` gets a `width` and `height` | `#bench-mark`'s `naturalWidth` (HTTP cache off); the harness refreshes the page every 250 ms (`extra[\"reloads\"]`) |\n| `hmr.reconnect` | none: SIGKILL of granian's worker, then SIGHUP to its supervisor, since granian's dev reloader never respawns a worker that died on its own | `#count` changes on `/counter`; the harness clicks `#increment` every 250 ms |\n| `hmr.watcher` | the `leaf` literal | `latency` is granian's `Changes detected` line (its `reload_tick` is 100 ms) |\n\nEvery benchmark but `hmr.watcher` has a `.preview` twin for `--env preview`\n(reflex 0.9.8+). Preview serves a static build that a hot reload rebuilds and\nthat shows after a refresh, so preview twins whose change needs a new page\nreload it (waiting for its load event) every 250 ms until it shows\n(`extra[\"reloads\"]`).\n\n`full_reloads` records whether the sample's page reloaded to show the change\n(the mark carries the document's `tab.alive()` tag; a reloaded document lost\nit). For the render, handler and reconnect benchmarks a reload is no hot\nupdate: `conclude` fails the sample with `FullReloadError`, also when the page\nreloads right after showing the hot update, so `latency` only holds hot\nupdates. For `hmr.css` a reload may be how the change shows: `latency` is the\ntime until it shows. A change the page never shows by itself (no hot update,\nno reload, within the deadline) fails the sample: the harness does not refresh\na dev page for it. The error then says when granian saw the change, when the\nreload's last `[timing]` line came and whether the page reloaded, so it tells\nwhich side dropped the change. A stylesheet hot update that vite logged\n(`[vite] ... hmr update`) 5 s ago without the page applying it fails the sample\nat once (`DroppedUpdateError`, naming the value the page still shows) instead\nof waiting the deadline out. `hmr.asset` refreshes the page itself in every\nmode: vite has no module for a file of `public/`, so a change to one reaches\nno page and a user refreshes for it; `latency` is the time until a refresh\nshows the new file and `extra[\"reloads\"]` counts the refreshes.\n`extra[\"hops\"]` places each sample's backend steps, in seconds\nsince the edit: `watcher_seen_s` (granian's line), `compile_done_s` (the\nreload's last `[timing]` line) and `dom_updated_s` (the page's mark).\n\n## Size budgets\n\n`size.export[app=playground]` (suites `pr` and `daily`) measures what a\nproduction build of `examples/playground` ships. Its `setup` copies the files\ngit tracks of the example into the instance's work directory (each arm of an\n`ab` run gets its own copy; `--keep` keeps it) and runs `reflex export\n--frontend-only --no-zip --env prod` there; bun stays cached in reflex's data\ndirectory under the cache directory. `sample` then measures the files on disk.\nOne export gives every metric, and every metric is exact, so one sample is\ntaken:\n\n| Metric | What |\n| --- | --- |\n| `initial_raw`, `initial_gzip`, `initial_brotli` | The JS and CSS the first page loads: the files the prerendered `index.html` references with `<link rel=\"modulepreload\">`, `<link rel=\"stylesheet\">` or `<script src>`. URLs of other hosts are not part of the build. |\n| `total_raw`, `total_gzip`, `total_brotli` | Every file of `.web/build/client` except compression sidecars. |\n| `chunks` | The `.js` files of `.web/build/client/assets`. |\n| `web_dir` | The regular files under `.web` outside `node_modules` (build output, compiled pages, templates). |\n| `node_modules` | The regular files under `.web/node_modules`. Symlinks are neither followed nor counted, here and in `web_dir`. |\n\nThe harness compresses each file on its own, gzip at level 9 (`mtime=0`) and\nbrotli at quality 11. Reflex 0.9 writes `.gz` sidecars next to the build's files\n(`.br` and `.zst` too when configured) and 0.8.23 writes none, so sidecars are\nnever measured, only summed into the extra data's `sidecar_bytes`. Each sample's\nextra data also holds the per-file breakdown `files`: `raw`, `gzip`, `brotli` and\n`initial` for each file of the client build, keyed by its path with the content\nhash of names in `assets/` replaced (`assets/chunk-5KNZJZUH-q9CrfzJj.js` becomes\n`assets/chunk-5KNZJZUH-HASH.js`; `#2` marks a second name that differed only in\nits hash), plus `initial_files` in page order, `html` (the page parsed),\n`reflex_version`, `fixture_hash` (the playground's committed `.content-hash`,\nthe hash the result series are keyed on and that CI keeps current; an\nuncommitted playground edit shows in the subject's `dirty` flag instead),\n`bun_lock` (the hash of `.web/bun.lock`) and the `compressors`' versions. Apps\nwith a `frontend_path` are not s\n\n<!-- [TRUNCATED AT 50KB] -->","packages/reflex-build-sdk/README.md":"# reflex-build-sdk\n\nPython client for the [Reflex Build](https://build.reflex.dev) API, with synchronous and asynchronous interfaces.\n\nInstall it with the HTTP library the client should send requests with:\n\n```bash\npip install \"reflex-build-sdk[httpx2]\"   # ReflexBuild and AsyncReflexBuild\npip install \"reflex-build-sdk[aiohttp]\"  # AsyncReflexBuild only\npip install \"reflex-build-sdk[httpx]\"    # ReflexBuild and AsyncReflexBuild\n```\n\nWithout any of them, pass the client a [transport](#transports) of your own.\n\n```python\nfrom reflex_build_sdk import ReflexBuild\n\nwith ReflexBuild() as client:\n    me = client.auth.me()\n    print(me.email, me.tier)\n```\n\n```python\nfrom reflex_build_sdk import AsyncReflexBuild\n\nasync with AsyncReflexBuild() as client:\n    me = await client.auth.me()\n```\n\n## Apps and projects\n\n```python\nfrom reflex_build_sdk import ReflexBuild\n\nwith ReflexBuild() as client:\n    projects = client.projects.search(\"default\")\n    project = projects[0] if projects else client.projects.create(\"default\")\n    app = client.apps.create(\"dashboard\", project_id=project.id)\n    client.apps.secrets.set(app.id, {\"OPENAI_API_KEY\": \"sk-...\"})\n\n    for deployment in client.apps.history(app.id):\n        print(deployment.status, deployment.url)\n\n    for record in client.apps.logs(app.id, search=\"error\"):\n        print(record.timestamp, record.message)\n```\n\n`client.apps` lists, creates, renames, moves, starts, stops, pauses, scales, rolls back and deletes apps, changes their settings, and reads their status, running deployment, deployment history and runtime logs; `client.apps.secrets` manages their secrets. `client.projects` lists, searches, creates, renames and deletes projects and reads their audit logs, with `projects.roles` (including custom roles), `projects.members` and `projects.teams` for access control. `AsyncReflexBuild` has the same methods as coroutines, with `logs` as an async iterator.\n\n### Custom domains\n\n```python\nfor record in client.apps.domains.add(app.id, \"app.example.com\").values():\n    print(record.type, record.name, record.value)\n\ndomain = client.apps.domains.get(app.id)\nprint(domain.status, domain.status_detail)\n```\n\n`domains.add` returns the DNS records to create, and `domains.get` checks them and reports whether the domain is ready to serve the app. Custom domains need the Pro or Enterprise plan.\n\n## Deploying\n\n```python\nfrom reflex_build_sdk import DeploymentFailedError, ReflexBuild\n\nwith ReflexBuild() as client:\n    urls = client.apps.reserve_hostname(app.id, app.name)\n    # Export the app against urls.frontend_url and urls.backend_url, e.g. with\n    # `reflex export`, producing backend.zip and frontend.zip.\n    deployment_id = client.deployments.create(\n        app.id,\n        backend=\"backend.zip\",\n        frontend=\"frontend.zip\",\n        regions={\"sjc\": 1},\n        on_upload_progress=lambda sent, total: print(f\"{sent}/{total} bytes\"),\n    )\n    try:\n        report = client.deployments.wait(deployment_id, on_status=print, timeout=900)\n    except DeploymentFailedError as error:\n        print(error.report.reason, error.report.guidance)\n        print(error.report.build_log_excerpt)\n        raise\n```\n\n`deployments.create` streams the archives straight to storage, then submits the deployment. `deployments.wait` returns the deployment's report once it is running, or awaiting approval (`report.status == \"AwaitingApproval\"`), and raises `DeploymentFailedError` if it fails. `deployments.status`, `report` and `build_logs` read a deployment's progress, and `regions` and `vm_types` list what can be deployed to.\n\n### Environments\n\nGive an app a pipeline of a dev and a production environment:\n\n```python\npipeline = client.apps.environments.enable(app.id)\nproduction_id = pipeline.production_environment_id\n```\n\nAn app that has a pipeline already is read rather than enabled again, which fails:\n\n```python\ndev, production = client.apps.environments.list(app.id)\nproduction_id = production.id\n```\n\nDeployments go to the first environment, and later ones run a version promoted from the one before:\n\n```python\ndeployment_id = client.deployments.create(\n    app.id, backend=\"backend.zip\", frontend=\"frontend.zip\"\n)\nclient.deployments.wait(deployment_id)\npromotion = client.apps.environments.promote(app.id, production_id)\nclient.deployments.wait(promotion.deployment_id)\n```\n\nEach environment has its own secrets and URL, and production keeps the app's own id and history. `environments.create`, `update`, `reorder`, `copy_missing_secrets` and `delete` manage the rest of the pipeline. Pipelines need the Enterprise plan.\n\n### Managed database\n\n```python\ndatabase = client.apps.database.create(app.id)\nprint(database.masked_connection_string)\n```\n\n`client.apps.database` creates a Postgres database for an app, shared by all of its environments, and sets its connection strings as secrets, `DATABASE_URL` among them, which each environment picks up on its next deployment. Creating or deleting a database needs a token with full access, which `reflex login` tokens are not, and an app with its own `DATABASE_URL` secret is refused.\n\n### Signing users in\n\n```python\nclient.apps.sign_in.enable(app.id)\nclient.apps.sign_in.set_audience(app.id, \"invited\")\nclient.apps.sign_in.invite(app.id, \"someone@example.com\")\n```\n\n`client.apps.sign_in` lets an app's users sign in with their Reflex accounts, through `rxe.AuthPlugin` from `reflex-enterprise`. It sets the app's sign-in settings as secrets, which take effect when the app is next deployed with `rxe.AuthPlugin`, chooses who may sign in, and lists, exports and blocks the app's users. Restricting who may sign in and inviting addresses need the Pro or Enterprise plan. Changing sign-in needs a token with full access; tokens from `reflex login` are refused.\n\n### Third-party connections\n\n```python\n# Inside a deployed app, which is started with its own access token.\nwith ReflexBuild() as client:\n    token = client.apps.connections.credential(app_id, \"openai\").access_token\n    # ... and for one of the app's users:\n    token = client.apps.connections.credential(\n        app_id, \"openai\", end_user=user_id\n    ).access_token\n```\n\n`client.apps.connections` calls third-party services an app is connected to without the app holding their keys: Reflex Build stores the credentials and hands out a live one per call, so read one for each call rather than storing it. `connect_link` starts a connection and returns the page to send someone to, `status` and `list` report what is connected, and `disconnect` ends it. A connection belongs either to the app or to one of its users, named with `end_user`. These need the app's own token, so a client built with no arguments inside a deployed app is already the right one.\n\n## Authentication\n\nThe client uses the `token` argument, or the `REFLEX_ACCESS_TOKEN` environment variable when none is passed.\n\nTo log in through the browser:\n\n```python\nimport webbrowser\n\nfrom reflex_build_sdk import ReflexBuild\n\nwith ReflexBuild() as client:\n    login = client.auth.begin_login()\n    print(f\"Approve the login at {login.url}\")\n    webbrowser.open(login.url)\n    token = client.auth.finish_login(login, timeout=600)\n\nwith ReflexBuild(token=token) as client:\n    print(client.auth.me().email)\n```\n\n`client.auth.tokens.revoke_self()` revokes the client's own token, which any token may do. Create a token for CI with `client.auth.tokens.create(\"ci\", expires_in_days=30)`, whose `.token` holds the value, and rotate or revoke one with `client.auth.tokens.refresh(token)`, whose `.token` holds the new value, and `client.auth.tokens.revoke(token)`. If a refresh answers `previous_revoked=False`, the old token is still live and needs revoking. Managing other tokens needs a token with full access, which `reflex login` tokens are not.\n\n`client.usage.balance()` reports how much of the organization's plan allowance is used, and `client.usage.history()` iterates over its charges and credits.\n\n### Pointing at another deployment\n\nThe client sends its requests to `https://build.reflex.dev`, or to the `base_url` argument, the `REFLEX_BUILD_BACKEND_URL` environment variable or `REFLEX_CLOUD_BACKEND_URL`, in that order. `begin_login` builds its approval URL the same way, from `ui_url`, `REFLEX_BUILD_URL` or `REFLEX_CLOUD_URL`, and falls back to the client's `base_url`. `reflex-hosting-cli` reads only the `REFLEX_CLOUD_*` names, so set those too for `reflex deploy` to reach the same deployment.\n\n## Security reviews\n\n```python\nreview_id = client.security_reviews.submit(\"source.zip\")\nresult = client.security_reviews.wait(review_id, timeout=600)\nfor violation in result.violations:\n    print(violation.severity, violation.file_path, violation.line, violation.message)\n```\n\nSecurity reviews need the Pro or Enterprise plan.\n\n## Google Cloud\n\nApps can run on an organization's own Google Cloud instead of Reflex Build:\n\n```python\nstatus = client.providers.gcp_status(client.auth.me().org_id)\nif status.configured and status.allowed:\n    client.apps.set_provider(app.id, \"gcp\")\n    client.apps.set_instance_bounds(app.id, min_instances=1, max_instances=10)\n```\n\nRunning on Google Cloud needs the Enterprise plan. `client.apps.set_full_deploy` also serves an app's frontend from Google Cloud, and `client.providers.cloud_run_manifest()` returns the Dockerfile and script to deploy to Cloud Run yourself.\n\nOrganization admins connect Google Cloud projects with a service account key:\n\n```python\nwith open(\"key.json\") as key_file:\n    client.providers.connect_gcp(\n        client.auth.me().org_id,\n        service_account_key=key_file.read(),\n        project_number=\"123456789012\",\n        region=\"us-central1\",\n    )\n```\n\n`client.providers.gcp_connections` adds, updates, verifies and removes further projects, rotates their keys and chooses the default, and `client.providers.disconnect_gcp` removes them all. These need a token with full access.\n\n## Errors\n\nEvery exception derives from `reflex_build_sdk.ReflexBuildError`. Error responses raise a subclass of `APIStatusError` matching the status code (`AuthenticationError`, `NotFoundError`, ...), carrying `status_code`, the server's `detail`, the `code` naming the condition where the API names one (e.g. `\"not_connected\"`), and the `request_id` to quote to support. Failed requests are retried up to `max_retries` times when repeating them cannot apply them twice: requests that never reached the server or were turned away with 408 or 429, and requests that are harmless to repeat (`GET`, `HEAD`, `OPTIONS` and `PUT` requests, and calls such as `apps.environments.update` that settle on the same result) that timed out, lost their connection, or got a 500, 502, 503 or 504 response.\n\n## Transports\n\n`AsyncReflexBuild` sends requests with the first installed of [aiohttp](https://docs.aiohttp.org), [httpx2](https://github.com/pydantic/httpx2) and [httpx](https://www.python-httpx.org), and `ReflexBuild` with httpx2, or httpx if httpx2 is not installed. Pass a transport from `reflex_build_sdk.transports` to configure the HTTP client, e.g. for proxies, or to pick the HTTP library:\n\n```python\nimport aiohttp\nimport httpx2\nfrom reflex_build_sdk import AsyncReflexBuild, ReflexBuild\nfrom reflex_build_sdk.transports import (\n    AiohttpTransport,\n    AsyncHttpx2Transport,\n    Httpx2Transport,\n)\n\n# Reads HTTP_PROXY, HTTPS_PROXY and NO_PROXY from the environment.\nasync with aiohttp.ClientSession(trust_env=True) as session:\n    async with AsyncReflexBuild(transport=AiohttpTransport(session)) as client:\n        ...\n\nclient = AsyncReflexBuild(transport=AsyncHttpx2Transport())\nclient = ReflexBuild(\n    transport=Httpx2Transport(httpx2.Client(proxy=\"http://proxy:8080\"))\n)\n```\n\nTo use another HTTP library, implement the `Transport` or `AsyncTransport` protocol.\n\nTo wrap the synchronous SDK's default transport without choosing an HTTP library,\ncall `reflex_build_sdk.transports.default_transport()`. It selects httpx2 when\ninstalled, otherwise httpx. Close the returned transport when finished; clients\nleave explicitly supplied transports open.\n","packages/reflex-build-sdk/openapi.json":"{\n  \"components\": {\n    \"schemas\": {\n      \"AccessJson\": {\n        \"description\": \"Serialized token access stored on the token row and in the AuthZ cache.\",\n        \"properties\": {\n          \"permissions\": {\n            \"additionalProperties\": {\n              \"type\": \"string\"\n            },\n            \"description\": \"Each permission the token holds, by key (`account`, `project`, `app`, `thread`), mapped to how much of it -- `none`, `read` or `write`.\",\n            \"title\": \"Permissions\",\n            \"type\": \"object\"\n          },\n          \"projects\": {\n            \"anyOf\": [\n              {\n                \"const\": \"all\",\n                \"type\": \"string\"\n              },\n              {\n                \"items\": {\n                  \"type\": \"string\"\n                },\n                \"type\": \"array\"\n              }\n            ],\n            \"description\": \"Which projects the project-scoped permissions above apply to: `all`, or the ids they are confined to.\",\n            \"title\": \"Projects\"\n          }\n        },\n        \"required\": [\n          \"permissions\",\n          \"projects\"\n        ],\n        \"title\": \"AccessJson\",\n        \"type\": \"object\"\n      },\n      \"AdminAppListEntry\": {\n        \"additionalProperties\": true,\n        \"description\": \"One row of the instance-admin app table.\\n\\nThe columns are fixed; what the request varies is the filter and the sort.\\nDeleted apps and projects are listed and flagged rather than hidden, since\\ntheir deployment rows outlive them and stay listed.\",\n        \"properties\": {\n          \"app_description\": {\n            \"description\": \"Free text the owner set.\",\n            \"title\": \"App Description\",\n            \"type\": \"string\"\n          },\n          \"app_id\": {\n            \"description\": \"The app's id.\",\n            \"format\": \"uuid\",\n            \"title\": \"App Id\",\n            \"type\": \"string\"\n          },\n          \"app_name\": {\n            \"description\": \"The app's name.\",\n            \"title\": \"App Name\",\n            \"type\": \"string\"\n          },\n          \"created_at\": {\n            \"description\": \"When the app row was created.\",\n            \"format\": \"date-time\",\n            \"title\": \"Created At\",\n            \"type\": \"string\"\n          },\n          \"deployment_count\": {\n            \"description\": \"Every deployment this app has ever had, on-prem rows included.\",\n            \"title\": \"Deployment Count\",\n            \"type\": \"integer\"\n          },\n          \"deployment_hostname\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The serving label it was given, nullable on the row and so absent independently of the deployment.\",\n            \"title\": \"Deployment Hostname\"\n          },\n          \"deployment_status\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"That deployment's status, null wherever `latest_deployment_id` is, as is `deployment_ts`. The two address fields between them are nullable on the deployment row itself, so either can be null while this is set.\",\n            \"title\": \"Deployment Status\"\n          },\n          \"deployment_ts\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"When that deployment's row was created, which a start or a rollback does not move.\",\n            \"title\": \"Deployment Ts\"\n          },\n          \"deployment_url\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The frontend a browser is pointed at. Null on a row whose serving host was never resolved -- a legacy row carries a bare `deployment_hostname` with no url -- so this is absent independently of the deployment.\",\n            \"title\": \"Deployment Url\"\n          },\n          \"full_deploy\": {\n            \"description\": \"Whether the whole app runs on the provider, frontend included, rather than serving its frontend from Reflex's CDN.\",\n            \"title\": \"Full Deploy\",\n            \"type\": \"boolean\"\n          },\n          \"is_deleted\": {\n            \"description\": \"Whether the app is soft-deleted.\",\n            \"title\": \"Is Deleted\",\n            \"type\": \"boolean\"\n          },\n          \"latest_deployment_id\": {\n            \"anyOf\": [\n              {\n                \"format\": \"uuid\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The app's current deployment -- a live or in-progress one before a terminal one, newest first, production identity only. Null for an app that has never deployed, and for one whose deployments are all on-prem, which this skips while `deployment_count` still counts them.\",\n            \"title\": \"Latest Deployment Id\"\n          },\n          \"org_id\": {\n            \"description\": \"The organization that owns the project.\",\n            \"format\": \"uuid\",\n            \"title\": \"Org Id\",\n            \"type\": \"string\"\n          },\n          \"org_name\": {\n            \"description\": \"That organization's name.\",\n            \"title\": \"Org Name\",\n            \"type\": \"string\"\n          },\n          \"project_id\": {\n            \"description\": \"The project the app is in.\",\n            \"format\": \"uuid\",\n            \"title\": \"Project Id\",\n            \"type\": \"string\"\n          },\n          \"project_is_deleted\": {\n            \"description\": \"Whether the project is soft-deleted. Deleting a project only queues its apps' own delete, so inside that window this is the app's only marker.\",\n            \"title\": \"Project Is Deleted\",\n            \"type\": \"boolean\"\n          },\n          \"project_name\": {\n            \"description\": \"That project's name.\",\n            \"title\": \"Project Name\",\n            \"type\": \"string\"\n          },\n          \"provider\": {\n            \"description\": \"Where the app deploys: Reflex's own hosting, or the org's cloud account.\",\n            \"title\": \"Provider\",\n            \"type\": \"string\"\n          },\n          \"vm_type_name\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Read from the machine rather than the deployment row: a size-scale rewrites the machines and leaves the row's own vmtype_id at the size it was deployed at.\",\n            \"title\": \"Vm Type Name\"\n          }\n        },\n        \"required\": [\n          \"app_id\",\n          \"app_name\",\n          \"app_description\",\n          \"provider\",\n          \"full_deploy\",\n          \"is_deleted\",\n          \"created_at\",\n          \"project_id\",\n          \"project_name\",\n          \"project_is_deleted\",\n          \"org_id\",\n          \"org_name\",\n          \"latest_deployment_id\",\n          \"deployment_status\",\n          \"deployment_url\",\n          \"deployment_hostname\",\n          \"deployment_ts\",\n          \"vm_type_name\",\n          \"deployment_count\"\n        ],\n        \"title\": \"AdminAppListEntry\",\n        \"type\": \"object\"\n      },\n      \"AdminAppMoveResponse\": {\n        \"description\": \"What the move did, in the shape the app route's own move answers.\\n\\nThe three repository fields come from ``move_shortfall_payload``, which both\\nmove paths share so they cannot come to spell a key differently -- a reader\\ntakes an absent key for a move that cost nothing. The destination is named\\n``target_project_id`` here and ``project_id`` there, which is the one\\ndifference and is what each has always answered with.\",\n        \"properties\": {\n          \"app_id\": {\n            \"description\": \"The app that moved.\",\n            \"format\": \"uuid\",\n            \"title\": \"App Id\",\n            \"type\": \"string\"\n          },\n          \"copied_integrations\": {\n            \"description\": \"The integrations copied across to the destination project.\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"title\": \"Copied Integrations\",\n            \"type\": \"array\"\n          },\n          \"message\": {\n            \"description\": \"What the move did, for a reader.\",\n            \"title\": \"Message\",\n            \"type\": \"string\"\n          },\n          \"permissions_repointed\": {\n            \"description\": \"Whether the app's authorization tuples were repointed at the destination project. False leaves who can reach the app answered by the *source* project until the periodic reconciler heals it -- the move landed, so this is reported rather than raised.\",\n            \"title\": \"Permissions Repointed\",\n            \"type\": \"boolean\"\n          },\n          \"repo_token_notices\": {\n            \"description\": \"The two lists above said in sentences, for showing somebody. Free text; read the lists to branch.\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"title\": \"Repo Token Notices\",\n            \"type\": \"array\"\n          },\n          \"repo_tokens_failed\": {\n            \"description\": \"Threads whose credential the hand-over could not write. The move landed, so these are reported rather than raised -- and nothing revisits them: those apps cannot push until somebody reconnects.\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"title\": \"Repo Tokens Failed\",\n            \"type\": \"array\"\n          },\n          \"repo_tokens_withheld\": {\n            \"description\": \"Threads whose repository credential was deliberately not handed over, because the destination is not entitled to it.\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"title\": \"Repo Tokens Withheld\",\n            \"type\": \"array\"\n          },\n          \"target_project_id\": {\n            \"description\": \"Where it moved to. Named `project_id` on the app route's own move, which is the one difference between the two shapes and is what each has always answered with.\",\n            \"format\": \"uuid\",\n            \"title\": \"Target Project Id\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"message\",\n          \"app_id\",\n          \"target_project_id\",\n          \"copied_integrations\",\n          \"repo_tokens_withheld\",\n          \"repo_tokens_failed\",\n          \"repo_token_notices\",\n          \"permissions_repointed\"\n        ],\n        \"title\": \"AdminAppMoveResponse\",\n        \"type\": \"object\"\n      },\n      \"AdminDeploymentListEntry\": {\n        \"additionalProperties\": true,\n        \"description\": \"One row of the instance-admin deployment table.\\n\\nFixed columns, for the reason the app table's are: the request varies the\\nfilter and the sort.\",\n        \"properties\": {\n          \"app_id\": {\n            \"description\": \"The app it belongs to.\",\n            \"format\": \"uuid\",\n            \"title\": \"App Id\",\n            \"type\": \"string\"\n          },\n          \"app_is_deleted\": {\n            \"description\": \"Whether the app is soft-deleted.\",\n            \"title\": \"App Is Deleted\",\n            \"type\": \"boolean\"\n          },\n          \"app_name\": {\n            \"description\": \"That app's name.\",\n            \"title\": \"App Name\",\n            \"type\": \"string\"\n          },\n          \"deployed_by_email\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"That account's address, where it still has one.\",\n            \"title\": \"Deployed By Email\"\n          },\n          \"deployed_by_id\": {\n            \"anyOf\": [\n              {\n                \"format\": \"uuid\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Who submitted it, null where that account has since been purged -- as are the two fields below it.\",\n            \"title\": \"Deployed By Id\"\n          },\n          \"deployed_by_username\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"And its display name, not a handle: derived from the address for a person, and the name an org admin chose for a service account.\",\n            \"title\": \"Deployed By Username\"\n          },\n          \"deployment_id\": {\n            \"description\": \"The deployment's id.\",\n            \"format\": \"uuid\",\n            \"title\": \"Deployment Id\",\n            \"type\": \"string\"\n          },\n          \"deployment_ts\": {\n            \"description\": \"When the row was created. Not when it went live: a start or a rollback re-parks a row that may be weeks old.\",\n            \"format\": \"date-time\",\n            \"title\": \"Deployment Ts\",\n            \"type\": \"string\"\n          },\n          \"description\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The submitter's changelog note for this deployment, not the app's own description.\",\n            \"title\": \"Description\"\n          },\n          \"hostname\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The serving label it was given.\",\n            \"title\": \"Hostname\"\n          },\n          \"persist\": {\n            \"description\": \"Exempt from idle suspension, so the app keeps a machine running with no traffic.\",\n            \"title\": \"Persist\",\n            \"type\": \"boolean\"\n          },\n          \"project_id\": {\n            \"description\": \"The project the app is in.\",\n            \"format\": \"uuid\",\n            \"title\": \"Project Id\",\n            \"type\": \"string\"\n          },\n          \"project_is_deleted\": {\n            \"description\": \"Deleting a project only queues its apps' soft-delete, so inside that window this is a row's only marker.\",\n            \"title\": \"Project Is Deleted\",\n            \"type\": \"boolean\"\n          },\n          \"python_version\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The Python version the build reported, which chose its base image.\",\n            \"title\": \"Python Version\"\n          },\n          \"reflex_version\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"What the app was built against, as the build reported it.\",\n            \"title\": \"Reflex Version\"\n          },\n          \"region_names\": {\n            \"description\": \"Where the deployment's machines are, empty if it has none.\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"title\": \"Region Names\",\n            \"type\": \"array\"\n          },\n          \"status\": {\n            \"description\": \"Where the deployment stands. This listing filters on nothing, so it carries every status the codebase writes: serving (`Running`, `Paused`, `Error: Out of Memory`), in flight (`Pending`, `AwaitingApproval`), never run (`Rejected`, `Superseded`, `Expired`) and finished (`Failed`, `Stopped`, `Historical`). The column is unconstrained text, so a legacy row can hold a value nothing writes any more -- `Removed` is the one still recognised, and an unlisted value is not a client error.\",\n            \"title\": \"Status\",\n            \"type\": \"string\"\n          },\n          \"strategy\": {\n            \"description\": \"How the rollout was made, as submitted: `immediate`, `rolling`, `bluegreen` or `canary`. `rolling` and `canary` are accepted on Fly only, and take the blue-green path.\",\n            \"title\": \"Strategy\",\n            \"type\": \"string\"\n          },\n          \"url\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The frontend a browser is pointed at.\",\n            \"title\": \"Url\"\n          },\n          \"vm_type_cpu\": {\n            \"anyOf\": [\n              {\n                \"type\": \"number\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"That machine's CPU count.\",\n            \"title\": \"Vm Type Cpu\"\n          },\n          \"vm_type_name\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Read from the machine rather than the row: a size-scale rewrites the machines and leaves `vmtype_id` at the size the deployment was made at. Null where no machine answered.\",\n            \"title\": \"Vm Type Name\"\n          },\n          \"vm_type_ram\": {\n            \"anyOf\": [\n              {\n                \"type\": \"number\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"That machine's memory, in GB, as the catalog stores it -- a 4096 MB machine reads 4.096.\",\n            \"title\": \"Vm Type Ram\"\n          },\n          \"vmtype_id\": {\n            \"description\": \"The machine size the row was deployed at, as stored. `GET /deployments/vm_types` resolves a catalog size and not the `custom-c<cpu>m<ram_mb>` id an explicit cpu/memory deploy mints, nor on-prem's `prem`; the `vm_type_*` fields below carry the shape either way.\",\n            \"title\": \"Vmtype Id\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"deployment_id\",\n          \"app_id\",\n          \"app_name\",\n          \"app_is_deleted\",\n          \"project_id\",\n          \"project_is_deleted\",\n          \"status\",\n          \"url\",\n          \"hostname\",\n          \"deployment_ts\",\n          \"reflex_version\",\n          \"python_version\",\n          \"persist\",\n          \"strategy\",\n          \"description\",\n          \"vmtype_id\",\n          \"vm_type_name\",\n          \"vm_type_ram\",\n          \"vm_type_cpu\",\n          \"deployed_by_id\",\n          \"deployed_by_email\",\n          \"deployed_by_username\",\n          \"region_names\"\n        ],\n        \"title\": \"AdminDeploymentListEntry\",\n        \"type\": \"object\"\n      },\n      \"AppAudience\": {\n        \"description\": \"Who an app will sign in.\\n\\nOnly ``PUBLIC`` admits somebody with no standing at all, which is why it is\\nthe one mode a change *to* needs no session sweep: every other value can\\nonly take admission away from somebody who holds it now, and a mode that\\nrefuses the next sign-in while leaving the current one running is not the\\ncontrol it says it is.\\n\\n``MEMBERS`` and ``INVITED`` are not ordered against each other. An invited\\nstranger is not a member, and a member is not necessarily invited, so\\n\\\"narrower\\\" is not a total order here and nothing tries to make it one --\\nwhich is why the sweep asks what is being moved *to* rather than comparing\\nthe two.\",\n        \"enum\": [\n          \"public\",\n          \"members\",\n          \"invited\",\n          \"owner_only\"\n        ],\n        \"title\": \"AppAudience\",\n        \"type\": \"string\"\n      },\n      \"AppAudienceChangedResponse\": {\n        \"description\": \"An audience change, and the sessions the narrowing ended.\\n\\n``changed`` is false where the mode was already the one asked for.\\n``revoked_sessions`` is a count and ``sweep_failed`` says whether it ran,\\nfor the reason a block's are.\",\n        \"properties\": {\n          \"audience\": {\n            \"description\": \"The mode the app is on now.\",\n            \"title\": \"Audience\",\n            \"type\": \"string\"\n          },\n          \"changed\": {\n            \"description\": \"False where it was already the one asked for.\",\n            \"title\": \"Changed\",\n            \"type\": \"boolean\"\n          },\n          \"revoked_sessions\": {\n            \"description\": \"How many sessions the narrowing ended. Zero where the sweep failed as well as where there were none -- `sweep_failed` tells those apart, for the reason a block's does.\",\n            \"title\": \"Revoked Sessions\",\n            \"type\": \"integer\"\n          },\n          \"sweep_failed\": {\n            \"description\": \"Whether ending the sessions the new mode refuses is still owed, which is weaker than any being left running: the sweep is one bulk call, so a failure leaves how many there were unknown -- an app nobody was signed in to reports this too. The mode is committed before the sweep, so the change applied either way. Whatever was signed in ends at the next refresh, and setting the mode again sweeps them.\",\n            \"title\": \"Sweep Failed\",\n            \"type\": \"boolean\"\n          }\n        },\n        \"required\": [\n          \"audience\",\n          \"changed\",\n          \"revoked_sessions\",\n          \"sweep_failed\"\n        ],\n        \"title\": \"AppAudienceChangedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAudienceResponse\": {\n        \"description\": \"Who an app signs in, and -- for a caller entitled to it -- who is invited.\\n\\n``audience`` is null where the stored mode is one this deployment does not\\nknow -- which refuses every sign-in, so it is not ``public``.\\n\\n``invites`` is null rather than absent for a caller who may read the mode\\nand not the list, which is a set of email addresses. One shape with a\\nnullable field rather than two shapes, because a caller cannot discriminate\\na union whose members differ only by a key being missing: an empty list and\\na withheld list read identically, and \\\"there is nobody invited\\\" is the\\nopposite answer to \\\"you may not see who is\\\".\",\n        \"properties\": {\n          \"audience\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Who the app signs in. Null where the stored mode is one this deployment does not know -- which refuses every sign-in, so it is not `public`.\",\n            \"title\": \"Audience\"\n          },\n          \"invites\": {\n            \"anyOf\": [\n              {\n                \"items\": {\n                  \"$ref\": \"#/components/schemas/AppAuthInviteResponse\"\n                },\n                \"type\": \"array\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Who is invited, or null for a caller who may read the mode and not the list. Nullable rather than absent, because an empty list and a withheld one read identically -- and `there is nobody invited` is the opposite answer to `you may not see who is`.\",\n            \"title\": \"Invites\"\n          }\n        },\n        \"required\": [\n          \"audience\",\n          \"invites\"\n        ],\n        \"title\": \"AppAudienceResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthAbsentResponse\": {\n        \"description\": \"An app the broker does not sign users in for.\\n\\n``client_enabled`` is reported either way: the client row can outlive the\\nkeys, so a half-torn-down app is visible as one rather than as clean.\",\n        \"properties\": {\n          \"client_enabled\": {\n            \"description\": \"Whether the broker will complete a login for this app. Written separately from the keys, so an app carrying them with the client row disabled refuses every sign-in -- which is why this is reported either way rather than implied by `has_auth`.\",\n            \"title\": \"Client Enabled\",\n            \"type\": \"boolean\"\n          },\n          \"has_auth\": {\n            \"const\": false,\n            \"description\": \"Always false on this body; the configured answer is the other member of the union.\",\n            \"title\": \"Has Auth\",\n            \"type\": \"boolean\"\n          },\n          \"kind\": {\n            \"description\": \"Which sign-in this app has, which `has_auth` alone cannot say: `none` is an app that signs nobody in, `managed` is the broker's, and `connected` is the app's own identity provider -- so a client offered \\\"set up sign-in\\\" can tell an app with nothing from one whose provider has to be disconnected first.\",\n            \"enum\": [\n              \"none\",\n              \"managed\",\n              \"connected\"\n            ],\n            \"title\": \"Kind\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"has_auth\",\n          \"client_enabled\",\n          \"kind\"\n        ],\n        \"title\": \"AppAuthAbsentResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthConfiguredResponse\": {\n        \"description\": \"An app the broker signs users in for, and as whom.\\n\\n``has_auth`` is what the app's own environment holds and\\n``client_enabled`` whether the broker will complete a login for it; an app\\ncarrying the keys with no enabled client row refuses every sign-in.\",\n        \"properties\": {\n          \"client_enabled\": {\n            \"description\": \"Whether the broker will complete a login for this app. Written separately from the keys, so an app carrying them with the client row disabled refuses every sign-in -- which is why this is reported either way rather than implied by `has_auth`.\",\n            \"title\": \"Client Enabled\",\n            \"type\": \"boolean\"\n          },\n          \"client_id\": {\n            \"description\": \"The app's OAuth client id, which is the app's own id. It is also the audience its identity tokens carry, so one app's token fails another app's check.\",\n            \"title\": \"Client Id\",\n            \"type\": \"string\"\n          },\n          \"has_auth\": {\n            \"const\": true,\n            \"description\": \"Always true on this body. It says what the app's own environment holds, which `client_enabled` beside it does not.\",\n            \"title\": \"Has Auth\",\n            \"type\": \"boolean\"\n          },\n          \"issuer\": {\n            \"description\": \"The OIDC issuer the app's client validates against. One per deployment, shared by every app -- what separates them is the audience, which is the app's own id.\",\n            \"title\": \"Issuer\",\n            \"type\": \"string\"\n          },\n          \"kind\": {\n            \"description\": \"Which sign-in this app has, which `has_auth` alone cannot say: `none` is an app that signs nobody in, `managed` is the broker's, and `connected` is the app's own identity provider -- so a client offered \\\"set up sign-in\\\" can tell an app with nothing from one whose provider has to be disconnected first.\",\n            \"enum\": [\n              \"none\",\n              \"managed\",\n              \"connected\"\n            ],\n            \"title\": \"Kind\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"has_auth\",\n          \"issuer\",\n          \"client_id\",\n          \"client_enabled\",\n          \"kind\"\n        ],\n        \"title\": \"AppAuthConfiguredResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthDeprovisionedResponse\": {\n        \"description\": \"A deprovisioning. ``deleted`` is false where there was nothing to take.\\n\\n``kind`` is what the app holds now, and is what separates the two ways\\n``deleted`` is false: an app that had no sign-in at all reads ``none``, and\\none carrying its own identity provider reads ``connected`` -- which this\\nroute deliberately does not touch, so the remedy is to disconnect that\\nrather than to retry here.\",\n        \"properties\": {\n          \"deleted\": {\n            \"description\": \"Whether this call took anything. False two ways, which `kind` separates: an app that had no sign-in at all, and one carrying its own identity provider, which this route deliberately does not touch.\",\n            \"title\": \"Deleted\",\n            \"type\": \"boolean\"\n          },\n          \"kind\": {\n            \"description\": \"Which sign-in this app has, which `has_auth` alone cannot say: `none` is an app that signs nobody in, `managed` is the broker's, and `connected` is the app's own identity provider -- so a client offered \\\"set up sign-in\\\" can tell an app with nothing from one whose provider has to be disconnected first.\",\n            \"enum\": [\n              \"none\",\n              \"managed\",\n              \"connected\"\n            ],\n            \"title\": \"Kind\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"deleted\",\n          \"kind\"\n        ],\n        \"title\": \"AppAuthDeprovisionedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthInviteCreatedResponse\": {\n        \"description\": \"One invited address, and whether *this* request is what added it.\\n\\n``created`` does not belong on the listing entry: it is a fact about one\\nrequest, and a row in a list has no request to be about.\",\n        \"properties\": {\n          \"created\": {\n            \"description\": \"Whether this request added the address. False means it was already invited and nothing changed, which the 200 rather than 201 also says.\",\n            \"title\": \"Created\",\n            \"type\": \"boolean\"\n          },\n          \"created_at\": {\n            \"description\": \"When it was invited.\",\n            \"format\": \"date-time\",\n            \"title\": \"Created At\",\n            \"type\": \"string\"\n          },\n          \"email\": {\n            \"description\": \"The invited address, folded -- which is the form the list is keyed by.\",\n            \"title\": \"Email\",\n            \"type\": \"string\"\n          },\n          \"redeemed\": {\n            \"description\": \"The same fact as a flag, for a client that only needs the yes or no.\",\n            \"title\": \"Redeemed\",\n            \"type\": \"boolean\"\n          },\n          \"redeemed_at\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"When somebody first signed in on it; null while nobody has.\",\n            \"title\": \"Redeemed At\"\n          }\n        },\n        \"required\": [\n          \"email\",\n          \"created_at\",\n          \"redeemed_at\",\n          \"redeemed\",\n          \"created\"\n        ],\n        \"title\": \"AppAuthInviteCreatedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthInviteResponse\": {\n        \"description\": \"One invited address, and whether anybody has signed in on it.\",\n        \"properties\": {\n          \"created_at\": {\n            \"description\": \"When it was invited.\",\n            \"format\": \"date-time\",\n            \"title\": \"Created At\",\n            \"type\": \"string\"\n          },\n          \"email\": {\n            \"description\": \"The invited address, folded -- which is the form the list is keyed by.\",\n            \"title\": \"Email\",\n            \"type\": \"string\"\n          },\n          \"redeemed\": {\n            \"description\": \"The same fact as a flag, for a client that only needs the yes or no.\",\n            \"title\": \"Redeemed\",\n            \"type\": \"boolean\"\n          },\n          \"redeemed_at\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"When somebody first signed in on it; null while nobody has.\",\n            \"title\": \"Redeemed At\"\n          }\n        },\n        \"required\": [\n          \"email\",\n          \"created_at\",\n          \"redeemed_at\",\n          \"redeemed\"\n        ],\n        \"title\": \"AppAuthInviteResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthProvisionedResponse\": {\n        \"description\": \"A provisioning. ``created`` is false where it was already there.\\n\\nCarries ``client_enabled`` like the read does, and for its reason: the two\\nhalves are written separately, so a provision that wrote the keys and left\\nthe client row disabled would otherwise answer exactly as a working one.\",\n        \"properties\": {\n          \"client_enabled\": {\n            \"description\": \"Whether the broker will complete a login for this app. Written separately from the keys, so an app carrying them with the client row disabled refuses every sign-in -- which is why this is reported either way rather than implied by `has_auth`.\",\n            \"title\": \"Client Enabled\",\n            \"type\": \"boolean\"\n          },\n          \"client_id\": {\n            \"description\": \"The app's OAuth client id, which is the app's own id. It is also the audience its identity tokens carry, so one app's token fails another app's check.\",\n            \"title\": \"Client Id\",\n            \"type\": \"string\"\n          },\n          \"created\": {\n            \"description\": \"Whether this call provisioned it; false where it was already there.\",\n            \"title\": \"Created\",\n            \"type\": \"boolean\"\n          },\n          \"has_auth\": {\n            \"const\": true,\n            \"description\": \"Always true: the provisioning wrote the keys.\",\n            \"title\": \"Has Auth\",\n            \"type\": \"boolean\"\n          },\n          \"issuer\": {\n            \"description\": \"The OIDC issuer the app's client validates against. One per deployment, shared by every app -- what separates them is the audience, which is the app's own id.\",\n            \"title\": \"Issuer\",\n            \"type\": \"string\"\n          },\n          \"kind\": {\n            \"description\": \"Always `managed` here, since a provision that answered anything else would have refused. Carried so the three sign-in routes report one field rather than three shapes a client has to tell apart.\",\n            \"enum\": [\n              \"none\",\n              \"managed\",\n              \"connected\"\n            ],\n            \"title\": \"Kind\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"has_auth\",\n          \"issuer\",\n          \"client_id\",\n          \"created\",\n          \"client_enabled\",\n          \"kind\"\n        ],\n        \"title\": \"AppAuthProvisionedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthUninvitedResponse\": {\n        \"description\": \"An address taken off the invite list, and the sessions it held.\\n\\nThe address is echoed folded, which is the form the list is keyed by.\",\n        \"properties\": {\n          \"email\": {\n            \"description\": \"The address taken off the list, echoed folded.\",\n            \"title\": \"Email\",\n            \"type\": \"string\"\n          },\n          \"revoked_sessions\": {\n            \"description\": \"How many sessions the withdrawn invite had admitted. Zero where the sweep failed, where the route could not work out whose sessions to end -- the address is resolved to an account after the delete commits -- and where there were none. `sweep_failed` covers the first two; `withdrawn` says whether there was a row to take.\",\n            \"title\": \"Revoked Sessions\",\n            \"type\": \"integer\"\n          },\n          \"sweep_failed\": {\n            \"description\": \"Whether ending that address's sessions is still owed, which is weaker than one still running: the flag is set by a failure to resolve the address at all, and it may hold no account or be admitted by the app whatever the list says. The row is deleted before any of it, so the withdrawal applied either way -- ``withdrawn`` says whether there was one to take.\",\n            \"title\": \"Sweep Failed\",\n            \"type\": \"boolean\"\n          },\n          \"withdrawn\": {\n            \"description\": \"Whether there was an invite to take. The route is idempotent, so withdrawing one that is not there is a success -- this is what separates that from a withdrawal that removed something, which the session count cannot: an address nobody invited can still be holding a session a peer's withdrawal left behind, and one that was on the list can be holding none.\",\n            \"title\": \"Withdrawn\",\n            \"type\": \"boolean\"\n          }\n        },\n        \"required\": [\n          \"email\",\n          \"revoked_sessions\",\n          \"sweep_failed\",\n          \"withdrawn\"\n        ],\n        \"title\": \"AppAuthUninvitedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthUserBlockedResponse\": {\n        \"description\": \"A block or unblock, in its two halves.\\n\\n``revoked_sessions`` counts what the sweep ended; ``sweep_failed`` is what\\nsays whether it ran. A sweep that failed reports zero and sets the flag,\\nrather than a null the flag beside it already says more about.\",\n        \"properties\": {\n          \"blocked\": {\n            \"description\": \"Where they stand now. On a 2xx this is what was asked for: an unblock that left them blocked -- because the sweep failed, or because a newer block stands -- is refused rather than answered here.\",\n            \"title\": \"Blocked\",\n            \"type\": \"boolean\"\n          },\n          \"blocked_at\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"When the block was made; null once it is lifted.\",\n            \"title\": \"Blocked At\"\n          },\n          \"revoked_sessions\": {\n            \"description\": \"How many live sessions were ended. Zero where the sweep failed as well as where there were none to end -- `sweep_failed` is what tells those apart, and it is the field to read.\",\n            \"title\": \"Revoked Sessions\",\n            \"type\": \"integer\"\n          },\n          \"sweep_failed\": {\n            \"description\": \"Whether ending this person's live sessions is still owed. Only a **block** can answer true here: it is written before the sweep, so it applied and how many sessions outlive it is unknown -- the sweep is one bulk call, so a person who was holding none reports this too. An **unblock** lifts the flag after, so a failed sweep deliberately leaves them blocked and changes nothing -- which is a 503 rather than a success, since there is no sense in which the request applied.\",\n            \"title\": \"Sweep Failed\",\n            \"type\": \"boolean\"\n          },\n          \"user_id\": {\n            \"description\": \"The subject the block is about.\",\n            \"title\": \"User Id\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"user_id\",\n          \"blocked\",\n          \"blocked_at\",\n          \"revoked_sessions\",\n          \"sweep_failed\"\n        ],\n        \"title\": \"AppAuthUserBlockedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthUserListResponse\": {\n        \"description\": \"A page of an app's users, and how many people there are in all.\\n\\n``search`` is echoed stripped, which is the term the page was filtered on.\",\n        \"properties\": {\n          \"limit\": {\n            \"description\": \"How many rows this page holds at most.\",\n            \"title\": \"Limit\",\n            \"type\": \"integer\"\n          },\n          \"offset\": {\n            \"description\": \"Where it started.\",\n            \"title\": \"Offset\",\n            \"type\": \"integer\"\n          },\n          \"search\": {\n            \"description\": \"The term the page was filtered on, echoed stripped -- which is the form it was applied in.\",\n            \"title\": \"Search\",\n            \"type\": \"string\"\n          },\n          \"total\": {\n            \"description\": \"How many match in all, so a client can page without walking to the end.\",\n            \"title\": \"Total\",\n            \"type\": \"integer\"\n          },\n          \"users\": {\n            \"description\": \"This page of the app's users.\",\n            \"items\": {\n              \"$ref\": \"#/components/schemas/AppAuthUserResponse\"\n            },\n            \"title\": \"Users\",\n            \"type\": \"array\"\n          }\n        },\n        \"required\": [\n          \"users\",\n          \"total\",\n          \"limit\",\n          \"offset\",\n          \"search\"\n        ],\n        \"title\": \"AppAuthUserListResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthUserResponse\": {\n        \"description\": \"One person an app has signed in.\\n\\nEach timestamp is named for the fact it holds: an agreement is not a\\nsign-in, and neither is a token refresh. ``last_active_at`` is null once\\nevery grant is gone rather than filled in from the consent beside it.\",\n        \"properties\": {\n          \"blocked\": {\n            \"description\": \"Whether the app refuses them a new sign-in. It does not end a session already running -- revoking their grants is what does that.\",\n            \"title\": \"Blocked\",\n            \"type\": \"boolean\"\n          },\n          \"blocked_at\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"When the app blocked them; null for somebody it has not.\",\n            \"title\": \"Blocked At\"\n          },\n          \"consented_at\": {\n            \"description\": \"Their last agreement. A sign-in that asked for nothing new leaves it alone, so it is when they last chose rather than when they were last here.\",\n            \"format\": \"date-time\",\n            \"title\": \"Consented At\",\n            \"type\": \"string\"\n          },\n          \"email\": {\n            \"description\": \"Withheld where the scope was: an app granted neither sees an opaque subject, so its owner is shown the same.\",\n            \"title\": \"Email\",\n            \"type\": \"string\"\n          },\n          \"first_consented_at\": {\n            \"description\": \"When they first agreed to sign in here, which is what created the row. Not a first sign-in: the code that consent minted can go unredeemed. It is the one instant that never moves, which is what the export pages on.\",\n            \"format\": \"date-time\",\n            \"title\": \"First Consented At\",\n            \"type\": \"string\"\n          },\n          \"last_active_at\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Their newest grant, which is as often a token renewal as a login -- deliberately not called a sign-in, since the row that *was* one goes with the prune. Null once every grant is gone rather than filled in from the consent beside it.\",\n            \"title\": \"Last Active At\"\n          },\n          \"name\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Withheld the same way as the address where the app was granted no profile scope.\",\n            \"title\": \"Name\"\n          },\n          \"user_id\": {\n            \"description\": \"The subject the app knows this person by: their platform account id, which is what the app's own code receives as `sub`.\",\n            \"title\": \"User Id\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"user_id\",\n          \"email\",\n          \"name\",\n          \"first_consented_at\",\n          \"last_active_at\",\n          \"consented_at\",\n          \"blocked_at\",\n          \"blocked\"\n        ],\n        \"title\": \"AppAuthUserResponse\",\n        \"type\": \"object\"\n      },\n      \"AppDatabaseAbsentResponse\": {\n        \"description\": \"An app with no managed database.\",\n        \"properties\": {\n          \"has_database\": {\n            \"const\": false,\n            \"description\": \"Always false on this body; the provisioned answer is the other member of the union.\",\n            \"title\": \"Has Database\",\n            \"type\": \"boolean\"\n          }\n        },\n        \"required\": [\n          \"has_database\"\n        ],\n        \"title\": \"AppDatabaseAbsentResponse\",\n        \"type\": \"object\"\n      },\n      \"AppDatabaseProvisionedResponse\": {\n        \"description\": \"A provisioning. ``created`` is false where one was already there.\",\n        \"properties\": {\n          \"created\": {\n            \"description\": \"Whether this call provisioned the database; false where one was already there and this answered with it.\",\n            \"title\": \"Created\",\n            \"type\": \"boolean\"\n          },\n          \"created_at\": {\n            \"description\": \"When it was provisioned.\",\n            \"title\": \"Created At\",\n            \"type\": \"string\"\n          },\n          \"database\": {\n            \"description\": \"The database name to connect to.\",\n            \"title\": \"Database\",\n            \"type\": \"string\"\n          },\n          \"has_database\": {\n            \"const\": true,\n            \"description\": \"Always true on this body; the no-database answer is the other member of the union, which carries it false.\",\n            \"title\": \"Has Database\",\n            \"type\": \"boolean\"\n          },\n          \"has_dev_branch\": {\n            \"description\": \"Whether a dev branch stands beside production, which is what a reset wipes. Without one a reset is refused unless the caller opts in by name, since the fallback would drop the deployed database.\",\n            \"title\": \"Has Dev Branch\",\n            \"type\": \"boolean\"\n          },\n          \"masked_connection_string\": {\n            \"description\": \"The connection string with its password removed. The real one is written into the app's own environment and is not served here.\",\n            \"title\": \"Masked Connection String\",\n            \"type\": \"string\"\n          },\n          \"project_id\": {\n            \"description\": \"The managed database project's id at the provider. Not the app id, which is only what the project is named after -- address the provider with this one.\",\n            \"title\": \"Project Id\",\n            \"type\": \"string\"\n          },\n          \"region\": {\n            \"description\": \"Where the database is provisioned.\",\n            \"title\": \"Region\",\n            \"type\": \"string\"\n          },\n          \"role\": {\n            \"description\": \"The role the connection string authenticates as.\",\n            \"title\": \"Role\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"has_database\",\n          \"project_id\",\n          \"region\",\n          \"created_at\",\n          \"database\",\n          \"role\",\n          \"masked_connection_string\",\n          \"has_dev_branch\",\n          \"created\"\n        ],\n        \"title\": \"AppDatabaseProvisionedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppDatabaseResponse\": {\n        \"description\": \"An app's managed database, with the connection string masked.\\n\\n``has_dev_branch`` is what a reset would wipe: without a dev branch,\\n``POST /database/reset`` drops the deployed database instead.\",\n        \"properties\": {\n          \"created_at\": {\n            \"description\": \"When it was provisioned.\",\n            \"title\": \"Created At\",\n            \"type\": \"string\"\n          },\n          \"database\": {\n            \"description\": \"The database name to connect to.\",\n            \"title\": \"Database\",\n            \"type\": \"string\"\n          },\n          \"has_database\": {\n            \"const\": true,\n            \"description\": \"Always true on this body; the no-database answer is the other member of the union, which carries it false.\",\n            \"title\": \"Has Database\",\n            \"type\": \"boolean\"\n          },\n          \"has_dev_branch\": {\n            \"description\": \"Whether a dev branch stands beside production, which is what a reset wipes. Without one a reset is refused unless the caller opts in by name, since the fallback would drop the deployed database.\",\n            \"title\": \"Has Dev Branch\",\n            \"type\": \"boolean\"\n          },\n          \"masked_connection_string\": {\n            \"description\": \"The connection string with its password removed. The real one is written into the app's own environment and is not served here.\",\n            \"title\": \"Masked Connection String\",\n            \"type\": \"string\"\n          },\n          \"project_id\": {\n            \"description\": \"The managed database project's id at the provider. Not the app id, which is only what the project is named after -- address the provider with this one.\",\n            \"title\": \"Project Id\",\n            \"type\": \"string\"\n          },\n          \"region\": {\n            \"description\": \"Where the database is provisioned.\",\n            \"title\": \"Region\",\n            \"type\": \"string\"\n          },\n          \"role\": {\n            \"description\": \"The role the connection string authenticates as.\",\n            \"title\": \"Role\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"has_database\",\n          \"project_id\",\n          \"region\",\n          \"created_at\",\n          \"database\",\n          \"role\",\n          \"masked_connection_string\",\n          \"has_dev_branch\"\n        ],\n        \"title\": \"AppDatabaseResponse\",\n        \"type\": \"object\"\n      },\n      \"AppFullDeployParams\": {\n        \"description\": \"Params for flipping only an app's full-deploy hosting mode.\",\n        \"properties\": {\n          \"full_deploy\": {\n            \"description\": \"Whether to bundle the frontend into the provider container and serve it beside the backend. GCP-only and Enterprise-only: true on an app hosted anywhere else is refused rather than ignored. Flipping a live app stops it, so the next redeploy comes up in the new mode.\",\n            \"title\": \"Full Deploy\",\n            \"type\": \"boolean\"\n          }\n        },\n        \"required\": [\n          \"full_deploy\"\n        ],\n        \"title\": \"AppFullDeployParams\",\n        \"type\": \"object\"\n      },\n      \"AppFullDeployResponse\": {\n        \"description\": \"An app's hosting mode after a flip.\\n\\nFlipping a live app stops it first, and ``stop_confirmed`` reports whether\\nthat whole teardown settled -- which is weaker than a confirmed destroy.\\nTrue where nothing was live.\",\n        \"properties\": {\n          \"full_deploy\": {\n            \"description\": \"The h\n\n<!-- [TRUNCATED AT 50KB] -->","packages/reflex-components-code/README.md":"# reflex-components-code\n\nReflex code display components.\n","packages/reflex-components-core/README.md":"# reflex-components-core\n\nUI components for Reflex.\n","packages/reflex-components-dataeditor/README.md":"# reflex-components-dataeditor\n\nReflex dataeditor components.\n","packages/reflex-components-gridjs/README.md":"# reflex-components-gridjs\n\nReflex gridjs components.\n","packages/reflex-components-internal/README.md":"# reflex-components-internal\n\nReflex internal components.\n","packages/reflex-components-lucide/README.md":"# reflex-components-lucide\n\nReflex lucide components.\n","packages/reflex-components-markdown/README.md":"# reflex-components-markdown\n\nReflex markdown components.\n","packages/reflex-components-moment/README.md":"# reflex-components-moment\n\nReflex moment components.\n","packages/reflex-components-plotly/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-components-plotly%2FREADME.md -->","packages/reflex-components-radix/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-components-radix%2FREADME.md -->","packages/reflex-components-react-player/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-components-react-player%2FREADME.md -->","packages/reflex-components-recharts/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-components-recharts%2FREADME.md -->","packages/reflex-components-sonner/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-components-sonner%2FREADME.md -->","packages/reflex-docgen/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-docgen%2FREADME.md -->","packages/reflex-hosting-cli/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-hosting-cli%2FREADME.md -->","packages/reflex-otel/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-otel%2FREADME.md -->","packages/reflex-release/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-release%2FREADME.md -->","packages/reflex-site-shared/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-site-shared%2FREADME.md -->","packages/reflex-workflow/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-workflow%2FREADME.md -->","packages/reflex-workflow/benchmarks/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-workflow%2Fbenchmarks%2FREADME.md -->","packages/reflex-workflow/examples/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-workflow%2Fexamples%2FREADME.md -->"},"files":{".claude/skills/prerelease-test/SKILL.md":"---\nname: prerelease-test\ndescription: Run the independent pre-release QA campaign for a Reflex release train. Discovers what shipped by reading every CHANGELOG.md on the pre-release branch, checks each package actually published to PyPI, then exercises the new features end-to-end in real apps driven by a real browser using ONLY published packages, upgrade-tests reflex-examples apps from the previous stable, regression-tests reflex-enterprise demos, audits wheel/sdist packaging, and produces a triaged FINDINGS.md plus a fix-before-release plan. Use this whenever a Reflex release is being prepared or checked — the user mentions a pre-release, an alpha/beta/rc, an `r/pre-*` branch, \"about to release\", release QA, validating a release candidate, or re-verifying that release-blocking fixes landed in a newer alpha. Also use it for the narrower slices on their own: smoke-testing published packages, upgrade/regression testing example apps against a new version, or auditing that packages ship their `.pyi` stubs in both wheel and sdist.\n---\n\n# Reflex pre-release testing\n\nThis skill runs the QA campaign that stands between a pre-release and a release: independent,\nadversarial, end-to-end exercise of what actually got published, from the perspective of a user\nwho runs `pip install reflex` and opens a browser.\n\nIts value comes from three habits, not from breadth of assertions:\n\n1. **Only published packages.** Everything installs from PyPI into throwaway venvs. The checkout\n   has unreleased code, different metadata, and a different dependency graph — testing it tells\n   you nothing about what users will get, and a package that failed to publish is itself a\n   release blocker you would otherwise miss.\n2. **Baseline against the previous stable.** A defect that also reproduces on the last release is\n   a bug; one that only reproduces on the new version is a regression and usually a blocker.\n   Without the baseline run you cannot tell them apart, and the triage that follows is guesswork.\n3. **Adversarially verify before reporting.** Have a second agent reproduce each claimed issue\n   from the written repro alone and actively try to refute it. In practice this refutes or\n   reclassifies a meaningful share of findings — and it is what makes the report trustworthy\n   enough for maintainers to act on directly.\n\n## Deliverables\n\nProduce these under `prerelease-testing/<date>-<version>/` in the repo and commit them to a work\nbranch as you go (never to `main`):\n\n- `FINDINGS.md` — executive summary, numbered findings with repro + evidence + regression status,\n  refuted claims, and per-cluster summaries. Templates: `references/reporting.md`.\n- `RELEASE_PLAN.md` — triage into fix-before-release vs file-as-issue. Rubric below.\n- One directory per test cluster containing the sample app sources (no `.web/`, `node_modules/`,\n  venvs), the driver scripts, `NOTES.md` with exact rerun commands, logs and screenshots.\n- `README.md` — what each cluster covers and how to reuse it for the next release.\n\nFindings must be reproducible by a stranger from `NOTES.md` alone. That is the bar: a fix agent\ngets handed the finding and nothing else.\n\n## Phases\n\nWork these in order. Phases 2–5 can overlap; 0 and 1 gate everything.\n\n### Phase 0 — Scope discovery\n\nFind the pre-release branch (`git ls-remote --heads origin 'r/pre-*'`, or the user names it), then\nread **every** `CHANGELOG.md` on it: the root one plus `packages/*/CHANGELOG.md`. The top entry of\neach is what this train ships.\n\nRun the discovery script to extract every package's version and confirm each is published:\n\n    uv run --script .claude/skills/prerelease-test/scripts/check_release_versions.py --ref <git-ref>\n\n(Script paths in this skill are repo-root-relative — the repo has its own unrelated `scripts/`\ndirectory, so the prefix matters.) It exits 1 when a package is confirmed missing and 2 when a\ncheck could not complete, so a proxy hiccup never reads as a missing package. An unpublished\nversion is a finding in its own right — report it immediately rather than working around it.\n\nRead the linked PRs for anything whose intent is not obvious from the changelog line; the GitHub\nMCP tools (`mcp__github__pull_request_read`) do this well. Understanding what a change was *for*\nis what lets you test it as a user rather than as a checklist.\n\n### Phase 1 — De-risk with a smoke test\n\nBefore any fan-out: one venv, `reflex init --template blank`, `reflex run`, then drive it in\nChromium with `.claude/skills/prerelease-test/scripts/drive_app.py`. This shakes out environment\nproblems (proxy, bun installs, browser path) once, in a context where you can debug them, instead\nof inside ten parallel agents.\n\nThe scripts carry PEP 723 metadata, so `uv run --script <path>` runs each one in its own isolated\nenvironment (the driver pulls in playwright that way); running them with an existing driver venv's\ninterpreter works too.\n\nAlso confirm the dependency graph resolves the way the changelog says it should (e.g. optional\ndependencies genuinely absent, sub-packages pinned as intended).\n\n### Phase 2 — Feature exploration fan-out\n\nDecompose the changelog into clusters of related changes and give each to its own agent, with an\nadversarial verification stage behind it. See `references/clusters.md` for how to cut the clusters\nand a standing coverage list; `references/orchestration.md` for the Workflow script, schemas and\nport map.\n\nThe instruction that makes this productive: **real-world exploration, not coverage filling.**\nCombine each new feature with the things users actually combine it with — State vars,\n`rx._x.client_state`, `rx.ComponentState`, `@rx.memo` wrapping, `rx.foreach`/`rx.cond`, event\nchains, background tasks, multiple pages and navigation, dev *and* prod mode. Bugs live in the\ninteractions, and the original PR's tests already cover the happy path.\n\nEvery run inspects all four channels: server log, browser console (errors *and* warnings), network\ntab (failed requests, 4xx/5xx), and the rendered page. Findings frequently show up in a channel\nnobody asserted on.\n\n### Phase 3 — Upgrade regression\n\nUsers upgrade in place; that path has its own failure modes (lockfile migration, pruned packages,\nstale `.web/`). Clone `reflex-dev/reflex-examples`, pick apps that span the feature surface —\nincluding ones using third-party packages (`reflex-local-auth`, `reflex-global-hotkey`) and\n`reflex[db]`/API apps — then for each:\n\n1. Install the **previous stable** (no `--prerelease` flag, so requirements resolve as a user's\n   would), run it, and drive its real user flows in the browser. This is your baseline.\n2. Upgrade the *same* venv and *same* app directory in place to the new version, preserving\n   `.web/` and `reflex.lock/`. Watch the first run's log closely — that is where migration\n   happens. Re-drive the identical flows and compare.\n3. Do one cold run (`rm -rf .web`) to check the fresh-install path converges to the same state.\n\nDiff `.web/package.json` before and after; unexpected dependency changes are findings.\n\n### Phase 4 — Enterprise regression\n\nDownstream breakage is the most common release blocker, because removing a public name is\ninvisible until something imports it. Install the **published** `reflex-enterprise` (never the\ncheckout) against the new reflex and run its demos — ag-grid, map, dnd, mantine, flow, the MCP\nplugin, OIDC. Baseline against the previous stable whenever something fails, so you can say\nwhether the new release broke it.\n\nBefore running anything, grep the published enterprise wheel for names the changelog says moved or\nwere removed; that finds the breakage in seconds instead of hours.\n\n### Phase 5 — Packaging audit\n\nAudit every package in the train; the discovery script feeds it the whole list. Chain the two with\n`&&`, never a pipe — a pipe reports only the audit's exit status, so a package whose PyPI check\nnever completed would be dropped from the list and the audit would still print PASS over what was\nleft. The `&&` is what makes that impossible: the audit runs only when discovery exits 0.\n\n    uv run --script .claude/skills/prerelease-test/scripts/check_release_versions.py \\\n      --ref <ref> --specs > specs.txt \\\n      && xargs uv run --script .claude/skills/prerelease-test/scripts/audit_pyi.py \\\n        --manifest-ref <ref> < specs.txt\n\nIt verifies each package ships its own generated `.pyi` stubs in **both** wheel and sdist, that\nthey are byte-identical between the two, that no package leaks another package's stubs, and that\ncounts line up with `pyi_hashes.json` (a package absent from the manifest must ship none).\n\nStub content hashes legitimately differ from the committed manifest because the build hook\nregenerates them at release time — compare *presence and counts*, and wheel against sdist.\n\n### Phase 6 — Triage and report\n\nWrite `FINDINGS.md` first (everything confirmed), then `RELEASE_PLAN.md` splitting findings into:\n\n**Fix before release** — anything meeting one of:\n- a confirmed regression against the previous stable,\n- security-relevant (path traversal, unauthenticated input handling, injection),\n- significant user impact, or trivially small to fix (a one-line guard, a missing default).\n\n**File as issues, fix after** — everything else, including pre-existing defects the campaign\nhappened to surface. Downstream (enterprise) issues go to that project's tracker, not this repo's.\n\nAlso flag decisions only a maintainer can make — an undocumented behavior change is either a bug\nor a missing changelog entry, and which one it is is their call. Ask rather than assume.\n\n### Phase 7 — Re-verify the next build\n\nWhen a new alpha ships with the fixes, re-run the *original failing repro* for each finding\n(not just the unit tests) against the new published packages, plus a general smoke. Append the\npass/fail table to `FINDINGS.md`. When the final ships, do one last stock-install smoke:\n`pip install reflex==<final>` with no prerelease flag, init, run, browser, and confirm the\nresolved graph is all-final.\n\n## Working rules\n\n- **Isolation.** Every agent gets its own venv and its own reserved port range; never install into\n  a shared venv. See the port map in `references/orchestration.md`.\n- **The traps are real.** `references/agent-brief.md` is the brief to hand every agent — it carries\n  the environment gotchas (checkout shadowing, proxy variables breaking installs) and the list of\n  known-benign console noise. Agents that skip it rediscover the same problems and report noise as\n  findings.\n- **Concurrency.** Dev servers are heavy (bun + vite + granian). On a 4-CPU box run about two\n  agents at a time and one dev server per agent; more just makes everything slow and flaky.\n- **Commit as you go.** Each cluster's artifacts land on the work branch when that cluster\n  finishes, so a long campaign is never one unrecoverable batch.\n- **Never fix framework code during the campaign.** Testing and fixing are separate engagements\n  with separate review standards; mixing them costs you the independence that makes the findings\n  credible. Record the repro and move on. (If the user then asks for fixes, that is a new task —\n  one PR per finding, regression test first, `references/reporting.md` has the PR conventions.)\n\n## Scaling the campaign\n\nFull campaign is roughly 30 agents over several hours. Scale down by dropping whole phases rather\nthan by testing each phase more shallowly — a shallow pass produces false confidence:\n\n- **Quick check** (~30 min): phases 0, 1, 5, plus grep-based downstream checks from phase 4.\n- **Standard** (~2 h): add phase 2 over the three or four highest-risk clusters.\n- **Full**: everything, with adversarial verification on every claimed issue.\n\nAsk the user which they want if the request is ambiguous and the difference matters.\n",".claude/skills/prerelease-test/references/agent-brief.md":"# The agent brief\n\nCopy this into the campaign scratchpad (e.g. `$SB/AGENT_BRIEF.md`), fill the `<...>` placeholders,\nand tell every test agent to read it first. It carries the rules that keep results trustworthy and\nthe environment traps that otherwise get rediscovered — expensively — by each agent in turn.\n\nKeep it in a file rather than pasting it into each prompt: agents re-read it when they get\nconfused, and updating one file updates the whole fleet.\n\n---\n\n## BRIEF TEMPLATE (copy from here)\n\nYou are one of several agents independently exercising the reflex `<VERSION>` pre-release\n(published `<DATE>`) as a real-world user of the framework. Your job: build small sample apps and\nrepro scripts for your assigned feature cluster, run them END-TO-END (real server, real Chromium),\nand hunt for anomalies. You REPORT issues; you never fix framework code.\n\n### HARD RULES\n\n1. **NEVER install reflex (or any workspace package) from the local checkout at `<REPO>`.** No\n   `uv sync`, no `uv run`, no `pip install -e`, no `uv pip install .` anywhere under it.\n   Everything installs from PyPI. We are testing what users receive, not what the tree contains.\n2. **Never run python with the checkout as your working directory.** `<REPO>/reflex/` shadows the\n   installed package, so `import reflex` silently picks up unreleased source and your results\n   become fiction. Run scripts from a neutral directory and start each repro with an assertion\n   naming the venv whose python is running it — the shared one below, or your own:\n   ```python\n   import reflex\n\n   assert \"<VENV_PATH>\" in reflex.__file__, reflex.__file__\n   ```\n   A guard that names some other venv fails on every run and gets deleted, which leaves you with\n   no guard at all.\n3. Reading the checkout is fine and encouraged — release source is on branch `<PRERELEASE_BRANCH>`.\n   For PR context load the GitHub MCP tools via ToolSearch (`select:mcp__github__pull_request_read`).\n4. Do NOT run any `git` write commands (add/commit/checkout/...) in the checkout. The orchestrator\n   commits artifacts.\n5. Do NOT fix bugs you find — record precise repro steps instead.\n6. Kill every server and browser you start before you finish (track PIDs; verify with `ps`). Other\n   agents share this machine — run at most ONE dev server at a time unless your cluster needs two.\n\n### Environment\n\n- Scratchpad root: `SB=<SCRATCHPAD>`\n- **Prebuilt shared venv (READ-ONLY — never install into it):** `$SB/envs/<SHARED_VENV>` has\n  `reflex==<VERSION>` and the alpha sub-packages. Use `$SB/envs/<SHARED_VENV>/bin/reflex` directly.\n- Need other deps or versions? Make your OWN venv:\n  ```\n  uv venv $SB/envs/<yours> --python 3.11\n  uv pip install --python $SB/envs/<yours>/bin/python --prerelease=allow 'reflex==<VERSION>' <extras>\n  ```\n  Always pass `--prerelease=allow` for alphas; PyPI is the default index — never point it at the\n  checkout. Python 3.12/3.13/3.14 are available via `uv venv --python 3.14` etc.\n- **Playwright driver venv:** `$SB/envs/driver/bin/python` (playwright, httpx, websockets).\n  Chromium: `/opt/pw-browsers/chromium` — launch with\n  `p.chromium.launch(executable_path=\"/opt/pw-browsers/chromium\")`.\n  A ready-made driver with console/network capture is at\n  `.claude/skills/prerelease-test/scripts/drive_app.py` in the checkout (read-only use is fine).\n- **Local HTTP needs proxy bypass on the CLIENT side only:** prefix curl/Playwright commands with\n  `NO_PROXY=localhost,127.0.0.1 no_proxy=localhost,127.0.0.1` (curl: `--noproxy '*'`).\n  Do NOT export those variables into the reflex server's environment — it breaks bun's package\n  installs through the proxy, which looks like a framework bug and is not.\n- Set `REFLEX_TELEMETRY_ENABLED=false` for every reflex command.\n- Node and bun are preinstalled. Enterprise apps need `CI=true` to bypass the dev login gate.\n- App working dirs: `$SB/apps/<cluster>/...`. Run servers on YOUR ASSIGNED PORTS:\n  `reflex run --frontend-port <FP> --backend-port <BP>`. The first run does a bun install (1–2 min);\n  poll the frontend URL until it returns 200 for up to ~6 minutes before concluding failure.\n- `--loglevel debug` gives verbose server logs; redirect to a file and actually read it.\n\n### What \"testing\" means here\n\n- Real-world exploration, not coverage filling. Combine the feature with State vars,\n  `rx._x.client_state`, `@rx.memo` wrapping, `rx.ComponentState`, `rx.foreach`/`rx.cond`, event\n  chains (`yield Other.handler()`), background tasks, multiple pages and navigation — whatever\n  plausibly interacts. The original PR already tested the happy path.\n- Drive the app in Chromium as a user would: click, type, navigate, upload, drag, use the keyboard.\n- On EVERY run capture and inspect: (a) the server log file, (b) browser console messages (errors\n  AND warnings), (c) failed requests / 4xx-5xx responses, (d) screenshots at key moments.\n- Baseline comparisons are what make findings actionable: if behavior looks wrong, check the\n  previous stable (`uv pip install 'reflex==<PREV_STABLE>'` in its own venv). Only-on-new is a\n  regression and high severity; both-versions is context worth noting, not a blocker.\n- Prod matters too: `reflex run --env prod` compiles and serves the built frontend. Test both modes\n  when your feature could differ (hydration, memoization, routing, prerender).\n\n### Known-benign noise — do not report these as findings\n\n- Browser console: the React Router \"💿 Hey developer\" HydrateFallback log, vite\n  `connecting.../connected` debug lines, the React DevTools download info line.\n- `reflex init` logging a few \"Failed to connect to https://registry.npmmirror.com\" lines before\n  falling back (this environment blocks that mirror). Do report it if the fallback itself fails.\n- Transient bun \"incorrect peer dependency\" warnings during a one-time upgrade migration, provided\n  the final lockfile is consistent.\n\nIf you see something surprising that is not on this list, investigate it — several real findings\nhave surfaced first as an unexplained warning.\n\n### Deliverables (mandatory)\n\n1. Copy reusable artifacts into the repo (plain `cp`/`rsync`, no git):\n   `DEST=<ARTIFACT_ROOT>/<cluster>/`\n   - the app source dirs, EXCLUDING `.web/`, `node_modules/`, `.states/`, `assets/external/`,\n     `*.db`, venvs\n   - your Playwright/repro scripts\n   - `NOTES.md`: what you tested, how to rerun it (exact commands), what you observed, including\n     benign quirks\n2. Return structured findings: every discrete check as a test entry (pass/fail/anomaly/skipped)\n   with enough repro detail that another agent can reproduce a failure from `NOTES.md` and your\n   scripts alone, without your conversation. An \"anomaly\" is anything surprising (console error,\n   warning, traceback, visual glitch, perf cliff) even when functionality works.\n\n### Timeboxing\n\nBe thorough but keep moving: if one sub-test resists debugging for ~10 minutes, record it as an\nanomaly with logs attached and continue. Finishing the whole cluster beats perfecting one test.\n",".claude/skills/prerelease-test/references/clusters.md":"# Cutting the changelog into clusters\n\nA cluster is one agent's assignment: a group of changelog entries that share a subsystem, so the\nagent can build one or two apps that exercise all of them together and notice how they interact.\n\n## How to cut them\n\nGroup by **where the change lives at runtime**, not by which PR shipped it. Entries that touch the\nsame subsystem belong together even when they came from unrelated PRs, because the interesting\nbugs are in their interaction — and one app can cover them all.\n\nAim for 8–12 clusters of 2–6 changelog entries each. A cluster that needs more than two apps is\ntoo big; one with a single trivial entry should be folded into a neighbour.\n\nEach cluster brief should carry:\n- the changelog lines verbatim (agents should not have to re-derive what shipped),\n- the PR numbers, so the agent can read intent,\n- concrete \"combine it with\" suggestions — this is what turns a checklist into exploration,\n- anything the entry implies but does not state (a perf claim to measure, a behavior that should\n  differ between dev and prod).\n\n## Standing coverage checklist\n\nMost Reflex releases touch some subset of these. Use it to check you have not left a shipped change\nunassigned, and as a source of interaction ideas.\n\n| Area | What to build | Interactions worth forcing |\n|---|---|---|\n| Routing / navigation | Multi-page app with dynamic (`[id]`), catchall (`[[...splat]]`) and static-sibling routes; slow `on_load` | Navigate away mid-`on_load`; two tabs on different dynamic values; browser back/forward; direct load vs client-side nav; prod mode |\n| State & event loop | Counter hammered by clicks while a background task writes | Background task + foreground handler racing; `yield`-streaming handlers; `async with self`; abrupt disconnect mid-stream |\n| Components / props | One page per changed component | Prop bound to a State var, to a `client_state` var, and inside `@rx.memo`; explicit `style=` merged with forwarded props |\n| Memoization | `@rx.memo` component with state-bound props and an event-handler prop, plus render counters | Memo in `rx.foreach`; memo wrapping `ComponentState`; two memos sharing a name in different modules; dev vs prod |\n| Typing / annotations | State vars using every annotation shape the entry mentions | Assign at runtime (not just compile); pass the handler *uncalled* to a trigger; run on the oldest and newest supported Python |\n| Uploads | `rx.upload` with buffered and streamed handlers | Hostile filenames (traversal, unicode, all-dots, spaces); raw multipart via httpx alongside browser uploads |\n| Logging / CLI | Run every CLI verb with and without the logging flags | Strict JSON-lines parsing of stdout; a user app that configures `logging` itself; missing optional sub-packages |\n| Config / plugins | App with the config knob set, unset, and set via env var | Deprecated form alongside the new form; plugin explicitly enabled vs implicit |\n| Build / prod / export | Multi-page app through `run --env prod`, `export`, `run --env preview` | Serve exported frontend statically with a backend-only server; inspect generated `.web/package.json`; custom component with a changed library |\n| Registration / multi-app | Two apps in one process; `AppHarness` twice | Sequential and simultaneous; check for registration leakage between them |\n| Optional dependencies | Bare install, each extra, and the upgrade path | Import the optional package's feature without the extra and judge the error message quality |\n| DevTools / perf | App with nested substates, custom components, client-only wrappers | Walk React fibers for `displayName`; record navigation main-thread cost; verify perf claims rather than trusting them |\n\n## Downstream and packaging clusters\n\nTwo clusters that are not feature-shaped but catch the highest-severity problems:\n\n- **Breaking-change surface.** For every entry under \"Breaking Changes\" (and every removal you spot\n  in the diff), ask what a downstream caller sees. Grep the published `reflex-enterprise` wheel and\n  the popular third-party packages (`reflex-local-auth`, `reflex-global-hotkey`) for the removed\n  names. A bare `AttributeError`/`ImportError` with no pointer to the replacement is a finding even\n  when the removal itself was intended.\n- **Packaging.** `.claude/skills/prerelease-test/scripts/audit_pyi.py`, plus a check that each package's declared dependency pins\n  match what the changelog says and that installing from the sdist works.\n",".claude/skills/prerelease-test/references/orchestration.md":"# Orchestrating the fleet\n\n## Choosing the mechanism\n\nInvoking this skill is itself the opt-in for the Workflow tool, so a full campaign should use it —\nthe explore→verify pipeline is deterministic control flow over many agents, exactly what Workflow\nis for. For a quick check or a single cluster, plain `Agent` calls are simpler and cheaper.\n\nUse one workflow per phase rather than one giant script. Phase results change what you want to ask\nnext (a cluster that finds a breaking change reshapes the enterprise phase), and you stay in the\nloop between phases.\n\n## The explore → verify pipeline\n\nThe shape that matters: each cluster's findings go straight into verification without waiting for\nthe other clusters. Use `pipeline`, not a barrier — a slow cluster should not hold up verification\nof a fast one.\n\n```js\nexport const meta = {\n  name: 'prerelease-explore',\n  description: 'Exercise <version> feature clusters end-to-end, then adversarially verify findings',\n  phases: [{ title: 'Explore' }, { title: 'Verify' }],\n}\n\nconst SB = '<scratchpad>'\nconst DEST = '<artifact root>'\n\nconst FINDINGS_SCHEMA = {\n  type: 'object',\n  required: ['cluster', 'summary', 'tests', 'issues', 'artifacts_dir'],\n  properties: {\n    cluster: { type: 'string' },\n    summary: { type: 'string' },\n    tests: {\n      type: 'array',\n      items: {\n        type: 'object',\n        required: ['name', 'status', 'details'],\n        properties: {\n          name: { type: 'string' },\n          status: { type: 'string', enum: ['pass', 'fail', 'anomaly', 'skipped'] },\n          details: { type: 'string' },\n          repro: { type: 'string' },\n        },\n      },\n    },\n    issues: {\n      type: 'array',\n      items: {\n        type: 'object',\n        required: ['title', 'severity', 'repro'],\n        properties: {\n          title: { type: 'string' },\n          severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low'] },\n          repro: { type: 'string' },\n          evidence: { type: 'string' },\n          regression: { type: 'boolean', description: 'true if the previous stable behaves correctly' },\n        },\n      },\n    },\n    artifacts_dir: { type: 'string' },\n  },\n}\n\nconst VERDICT_SCHEMA = {\n  type: 'object',\n  required: ['confirmed', 'notes'],\n  properties: {\n    confirmed: { type: 'boolean' },\n    notes: { type: 'string' },\n    root_cause_guess: { type: 'string' },\n  },\n}\n\nphase('Explore')\nconst results = await pipeline(\n  CLUSTERS,\n  (c, _item, i) => agent(brief(c, i), { label: `explore:${c.key}`, phase: 'Explore', schema: FINDINGS_SCHEMA }),\n  async (res, c, i) => {\n    if (!res) return { cluster: c.key, agent_died: true }\n    // Cap the fan-out per cluster. Issues past the cap are absent from verified_issues but\n    // still present in res.issues, which is how the report tells them from verified ones.\n    const issues = (res.issues || []).slice(0, 4)\n    if (!issues.length) return res\n    const verdicts = await parallel(\n      issues.map((iss, j) => () =>\n        agent(verifyBrief(c, iss, j), { label: `verify:${c.key}:${j}`, phase: 'Verify', schema: VERDICT_SCHEMA })\n          // A dead verifier resolves falsy. Give it its own marker: `verdict: null` would\n          // read as a verdict that cleared the issue, and dropping the entry would leave a\n          // hole indistinguishable from an issue the cap never sent to a verifier.\n          .then((v) => (v ? { issue: iss, verdict: v } : { issue: iss, verifier_died: true })),\n      ),\n    )\n    return { ...res, verified_issues: verdicts }\n  },\n)\n// Dead explorers stay in as `agent_died` markers rather than being filtered out: a cluster\n// that produced nothing is a hole in the campaign, and silently dropping it is how a hole\n// gets mistaken for a clean result. Same for `verifier_died` above. Every marker is work\n// the campaign did not do, so the report must account for each one rather than skip it.\nreturn results.filter(Boolean)\n```\n\nThe verifier's prompt is what makes this work. It must:\n- reproduce **from the written repro alone**, in its own working directory, not by reading the\n  reporter's conversation — that is simultaneously a test of the repro's quality,\n- be told to actively **refute**: is this an environment quirk, an API misuse, pre-existing on the\n  previous stable, or a genuine defect?\n- set `confirmed: true` only for a genuine defect a fix agent should act on,\n- append a `## VERIFICATION` section to the cluster's `NOTES.md` so the record travels with the\n  artifacts.\n\n## Port map\n\nGive every agent a disjoint range and tell it to always pass `--frontend-port/--backend-port`\nexplicitly. Never let anything use the defaults (3000/8000) — that is how two agents collide and\nproduce confusing, unreproducible results.\n\n| Stage | Frontend | Backend |\n|---|---|---|\n| Explore agent *i* | `3100 + 40i` … +19 | `8100 + 40i` … +19 |\n| Verify agent *i.j* | `3600 + 40i + 4j` … +3 | `8600 + 40i + 4j` … +3 |\n| Orchestrator smoke | 3050–3059 | 8050–8059 |\n\n## Prompt scaffolding for each agent\n\nEvery cluster prompt should open with the same preamble, then the cluster-specific brief:\n\n```\nFIRST read <SB>/AGENT_BRIEF.md and follow every rule in it (isolated PyPI-only installs — never\ninstall from the checkout; end-to-end browser testing; artifact + NOTES.md deliverables; kill your\nprocesses).\nYour cluster key: \"<key>\". Working dir: <SB>/apps/<key>/. Artifact destination: <DEST>/<key>/.\nYour RESERVED ports: frontend <FP_START>-<FP_END>, backend <BP_START>-<BP_END> — always pass them\nexplicitly, and never bind outside them.\n<cluster brief: changelog lines verbatim, PR numbers, combine-with suggestions>\nAlso in scope: anything adjacent you notice (log warnings, console anomalies, network errors,\nvisual glitches). Record benign-but-surprising observations in NOTES.md and as 'anomaly' entries.\n```\n\nFill the port ends from the table above, not from a fixed span: an explore agent's range is 20\nports wide and a verify agent's is 4. A verifier told it owns 20 would reach into the next\nverifier's range, which is the collision the map exists to prevent.\n\n## Running it\n\n- Two agents at a time is right for a 4-CPU box; the workflow's own concurrency cap handles the\n  rest of the queue.\n- Between phases, read the results before launching the next one.\n- Schedule a check-in (`send_later`, ~45 min) during long runs so a wedged agent or a leaked dev\n  server gets noticed. Check `ps` for stray `reflex run` processes and commit finished clusters.\n- When the workflow completes, its full structured result is in the task output file; parse it for\n  the report rather than re-reading transcripts.\n",".claude/skills/prerelease-test/references/reporting.md":"# Reporting\n\n## FINDINGS.md\n\nThe audience is a maintainer deciding what blocks the release, and fix agents who will get handed\none finding and nothing else. Write for both: a summary that supports a go/no-go call, and findings\nself-contained enough to act on in isolation.\n\n```markdown\n# Findings — reflex <version> pre-release testing (<date>)\n\n<One paragraph on method: PyPI-only isolated venvs, end-to-end browser runs, previous-stable\nbaselines, independent adversarial verification of every claimed issue. Agent count.>\n\n## Versions under test\n<Every package and version, noting which are new in this train and that each is published.>\n<Environment: OS, CPU/RAM, node/bun, python versions, browser.>\n\n## Executive summary\n<What works — name the headline changelog items verified.>\n<What blocks — the short list, with severity.>\n<Severity histogram, and the count of refuted claims.>\n\nIndex:\n- FINDING-001: <title> (SEVERITY)\n- ...\n\n## FINDING-00N: <title> (SEVERITY)\n\n- Cluster: `<cluster>` | Regression vs <prev stable>: yes/no | Verifier: CONFIRMED\n- Repro: <exact commands/steps, self-contained>\n- Evidence: <log excerpt, console error, screenshot path>\n- Root cause (verifier analysis): <file:line and mechanism, when known>\n- Verification notes: <what the independent reproducer found>\n\n## Refuted / reclassified claims\n- **<title>** (`<cluster>`): <why it is not an actionable defect for this release>\n\n## Cluster summaries\n### `<cluster>` (pass:N, anomaly:N, fail:N)\n<2-4 sentences: what was built, what was verified, what was found.>\n```\n\nTwo things carry disproportionate weight and are easy to skip:\n\n- **The refuted list.** It shows the findings were filtered, which is why a maintainer can trust the\n  ones that remain. Never quietly drop a refuted claim.\n- **Regression status on every finding.** \"Broken in both versions\" and \"newly broken\" lead to\n  opposite decisions, and the reader cannot recover that from the description.\n\n## RELEASE_PLAN.md\n\n```markdown\n# Release plan — what blocks <version> vs what gets filed\n\n## Already in flight\n| PR | Covers | Gap check |\n<For each open PR, which findings it addresses and — importantly — what it does NOT cover.>\n\n## Fix before release\n### Security\n### Confirmed regressions\n### High impact and/or trivially small\n<Each item: finding ref, one-line rationale tied to the rubric, and the shape of the fix.>\n\n## File as issues, fix after release\n### <this repo>\n### <downstream repo>\n\n## Decisions needed from a maintainer\n<Behavior changes that are either bugs or missing changelog entries — their call, not yours.>\n\n## Suggested sequencing\n<Order of PRs, noting which can land in parallel and which touch the same files.>\n```\n\nThe rubric (confirmed regression / security / significant-impact-or-trivial) is in `SKILL.md`.\nApply it visibly: each entry should say which arm of the rubric put it there, so the maintainer can\ndisagree with a specific judgment rather than the whole list.\n\n## Filing issues\n\nFor post-release items: search for duplicates first (2–3 keyword variants, open *and* closed), then\nfile with a self-contained repro, observed vs expected, environment, a note that it came from\n`<version>` pre-release testing, and a pointer to the artifacts branch and cluster directory.\nMirror `.github/ISSUE_TEMPLATE/bug_report.md` where it fits.\n\n## If the user asks for the fixes afterwards\n\nThat is a separate engagement. What worked well:\n\n- **One PR per finding**, branched from current `main`, in its own git worktree so parallel fix\n  agents never collide.\n- **Regression test first**: write it, show it failing against unfixed `main`, then fix, then show\n  it passing. Report both states in the PR body — a reviewer should not have to take it on faith.\n- **News fragment** under the right package's `news/` directory. The changelog CI gate checks per\n  package: a fix touching `packages/reflex-base/` needs a fragment in\n  `packages/reflex-base/news/`, and a root-only fragment will fail the gate.\n- **Adversarial review of each PR** before handing it over: an independent agent re-runs the\n  regression test against unfixed source to confirm it actually pins the bug, and checks repo\n  conventions. This catches PRs whose test passes either way.\n- PR body: cite the FINDING number and that it came from pre-release testing, describe the defect\n  mechanism, the fix, and the test plan including the failing-before evidence.\n- Watch CI after opening (`subscribe_pr_activity`) and drive each PR to green.\n","AGENTS.md":"# Coding Agent Guidelines\n\nReflex: Python web **framework** compiling to React. Monorepo using uv workspace — main package in `reflex/`, sub-packages in `packages/`, docs site in `docs/`.\n\n## Workflow\n\n1. **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.\n2. **Bugfixes:** write a regression test that fails before writing the fix.\n3. **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.\n\n## Commands\n\nUse `uv` for everything — never bare `python` or `python3`.\n\n```\nuv sync                                                          # install deps\nuv run pytest tests/units --cov --no-cov-on-fail --cov-report=   # unit tests (>=72% coverage)\nuv run pytest tests/integration                                  # integration tests (slow)\nuv run ruff check .                                              # lint\nuv run ruff format .                                             # format\nuv run pyright reflex tests                                      # type check\nuv run python scripts/check_min_deps.py                          # validate each package's declared minimum dep versions (pyright in isolated min-version envs; workspace siblings resolve from locally built wheels, all other deps from PyPI). CI passes --wheelhouse instead, reusing the build jobs' artifacts\nuv run python scripts/check_min_deps.py --check-dev-pins [pkg]    # fail if pkg (default: all) declares an unpublishable *.dev dependency pin (the publish workflow runs the same gate via `reflex-release check-dev-pins`)\nuv run reflex-release sync                                       # regenerate the release workflows after editing [tool.reflex-release] or the reflex-release templates\nuv run python scripts/make_pyi.py                                # regenerate .pyi stubs\nuv run pre-commit run --all-files                                # all pre-commit hooks\n```\n\n## Layout\n\n```\nreflex/                 # main framework package (app, state, compiler, components, utils, istate)\npackages/               # workspace sub-packages (reflex-base, reflex-components-*, reflex-docgen, reflex-components-internal)\ntests/units/            # unit tests, mirrors source tree\ntests/integration/      # Selenium integration tests (run in dev+prod modes)\n  tests_playwright/     # Playwright integration tests (preferred for new tests)\ntests/benchmarks/       # performance benchmarks\ndocs/                   # documentation site (separate workspace member)\n```\n\n## Code style\n\n- Concise, robust code. Reflex is a framework used in many ways — handle edge cases without unnecessary complexity.\n- 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.\n- Don't add expensive workarounds (e.g. `isinstance` checks) to paper over type-level problems — fix the root cause instead.\n- Don't repeat validation or be over-defensive; trust data that was already validated upstream.\n- Think in CPU cycles: avoid unnecessary data copies, redundant allocations, and gratuitous indirection.\n- Extract duplicated code into parameterized helpers.\n- No block comments (`# --- Section ---`, `# ============`). Plain inline comments only.\n- Be cautious creating new public APIs — they must be documented and supported long-term.\n- Google-style docstrings on all functions: one-line summary, optional detail sentence(s), then Args/Returns (or Yields)/Raises.\n- Prefer imports at the top of the module in isort order. Only use inline imports when necessary to avoid circular dependencies.\n\n## Testing\n\n- Write comprehensive tests for new/changed features; extend existing test files where possible.\n- Test functions at module level, not wrapped in classes.\n- **Unit tests:** `tests/units/`, run with `uv run pytest tests/units`.\n  - 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`).\n- **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.\n\n### Integration test patterns\n\nApps as factory functions, run via `AppHarness`:\n\n```python\ndef SomeApp():\n    import reflex as rx\n\n    class State(rx.State):\n        value: str = \"\"\n\n    def index():\n        return rx.box(rx.text(State.value))\n\n    app = rx.App()\n    app.add_page(index)\n\n\n@pytest.fixture(scope=\"module\")\ndef some_app(tmp_path_factory) -> Generator[AppHarness, None, None]:\n    with AppHarness.create(\n        root=tmp_path_factory.mktemp(\"some_app\"), app_source=SomeApp\n    ) as harness:\n        yield harness\n```\n\nPlaywright tests use the `page` fixture and navigate to `harness.frontend_url`. Utilities in `tests/integration/utils.py` (polling, event ordering, storage).\n\n## .pyi stubs\n\nWhen 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.\n\n## CI workflows\n\nBranch rules require one check per workflow, listed in\n`.github/rulesets/main-required-checks.json`. Check names are matched literally —\nno wildcards — so two rules follow:\n\n- **A required workflow must not filter its `pull_request` trigger.** A workflow\n  a path filter skips never reports its checks, so a required check on it blocks\n  the merge forever. Filter in a `changes` job instead and gate the real jobs on\n  `if: needs.changes.outputs.run == 'true'` — a job skipped by `if:` reports as a\n  pass. `push` triggers may keep their filters; nothing gates a merge there. So\n  may a workflow that blocks no merge — absent from the ruleset and listed in\n  that test's `ADVISORY` — where the filter costs a run rather than a merge.\n- **Every merge-blocking workflow ends in a gate job** named `<workflow>-gate`,\n  which collapses it into one check name that matrix expansion cannot move. The\n  exception is a workflow with one job whose name cannot drift — `pre-commit`,\n  `changelog` — which the ruleset requires by that name (`DIRECTLY_REQUIRED` in\n  the test). A gate looks like:\n\n```yaml\n  unit-tests-gate:\n    needs: [changes, unit-tests, unit-tests-macos]  # every other job\n    if: always()  # not !cancelled(): a cancelled run would report a pass\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@... # v6.0.2\n        with:\n          persist-credentials: false\n      - uses: ./.github/actions/ci_gate\n        with:\n          needs: ${{ toJSON(needs) }}\n```\n\nAdding a job means adding it to the gate's `needs`; adding a workflow means\nadding its gate to the ruleset. `tests/units/test_workflow_gates.py` fails when\neither drifts. Every matrix leg blocks through its gate, pre-release Python\nversions included, so leave `continue-on-error` off a gated job. A workflow\ndisabled in the repository's Actions settings never reports, which no test can\nsee: disabling one means moving it to `ADVISORY` and out of the ruleset, or every\nmerge waits on it.\n\n## Changelog fragments\n\nUser-facing changes need a news fragment in the `news/` directory of each\npackage they touch (the repo root's `news/` for `reflex`), named\n`+<slug>.<type>.md`. Putting the PR number in the name (`<PR number>.<type>.md`)\nis optional: the release process renames an orphan fragment when it can identify\nthe PR that added it, so its entry links to that PR. Don't push a commit just to\nrename one. Types: `breaking`, `deprecation`, `feature`, `bugfix`,\n`performance`, `docs`, `misc`.\n\nWrite for external downstream users, not for reviewers. Every entry links to\nits PR, so motivation, narrative, and implementation details belong in the PR\nand the commit message — a reader who wants them will follow the link. Keep the\nfragment to a sentence or two saying what changed and what it means for a user:\n\n> Reduce published wheel and sdist size by removing misplaced generated artifacts.\n\nBrevity is about the narrative, not the substance: whatever is genuinely useful\ndownstream belongs in the fragment. A brief usage example for a new feature, or\nthe before/after of converting deprecated usage to the supported style, earns\nits place. Once it runs past a few sentences and a small code block, it is\ndocumentation — write it under `docs/` and let the fragment link there.\n\nCI requires a fragment for every package whose source the PR touches; the\n`skip-changelog` label waives it for changes that are genuinely not user-facing.\n\n## Sibling dependency floors\n\nWhen a package needs an unreleased change in a workspace sibling, raise its\nfloor on that sibling to the `.dev0` of the sibling's next version. Every\npackage derives its version with `bump = true`, so each commit after its newest\ntag builds as a dev release of that next version:\n\n- after `reflex-base-v0.9.12`: `reflex-base >= 0.9.13.dev0`\n- after `reflex-components-core-v0.9.10.post1`: `reflex-components-core >= 0.9.10.post2.dev0`\n\nSuch a floor excludes every release up to that tag and is met by every later\ncommit, so check-min-deps passes. A post release of the sibling cut after the\nfloor was written leaves main building below it; re-floor at that post release.\nReleasing the dependent lifts it to the first\npublished version that satisfies it (see `packages/reflex-release/README.md`,\n\"Dependency pins across a release\"). A floor the workspace can't meet fails\ncheck-min-deps with \"builds as ... here\".\n\n## Breaking changes and deprecation\n\nReflex has downstream users — don't break them. Provide a fallback path during deprecation.\n\n**Runtime warning** via `console.deprecate()`:\n```python\nfrom reflex_base.utils import console\n\nconsole.deprecate(\n    feature_name=\"OldFeature\",\n    reason=\"Use NewFeature instead.\",\n    deprecation_version=\"<next dot version of latest git tag>\",\n    removal_version=\"1.0\",\n)\n```\nSet `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.\n\n**Type-level deprecation** for deprecated methods/overloads using `typing_extensions.deprecated`, always inside a `TYPE_CHECKING` guard to avoid double warnings:\n```python\nfrom __future__ import annotations\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from typing_extensions import deprecated\n\n    @deprecated(\"Use new_method() instead\")\n    def old_method(self) -> str: ...\n```\n\n## Checklist\n\nBefore submitting:\n1. Tests pass with adequate coverage\n2. `uv run ruff check .` and `uv run ruff format .` clean\n3. `uv run pyright reflex tests` passes\n4. `pyi_hashes.json` updated if components changed\n5. Documentation updated if user-facing behavior changed\n6. News fragment added for user-facing changes\n7. Deprecation warnings added if breaking changes introduced\n","CLAUDE.md":"AGENTS.md","packages/hatch-reflex-pyi/README.md":"# hatch-reflex-pyi\n\nHatch build hook that generates .pyi stubs for Reflex component packages.\n","packages/integrations-docs/README.md":"# reflex-integrations-docs\n\nReflex Integrations Docs.\n","packages/integrations-docs/src/integrations_docs/docs/airtable.md":"---\ntags: Data Infrastructure\ndescription: Connect your apps to Airtable to read, create, and update records in real time.\n---\n# Airtable Integration\n\nThe **Airtable Integration** lets your apps interact with Airtable bases to **store, fetch, and update structured data** directly from workflows, user actions, or automated triggers. Perfect for managing dynamic content, customer data, or workflows without complex backend setup.\n\n\n## What You Can Do\n\nWith the Airtable Integration, your app can:\n\n* Read and display data from Airtable bases\n* Create new records dynamically from user actions\n* Update or delete records through workflows\n* Power AI experiences with live database content\n* Sync structured data without hosting your own database\n\n## Step 1: Get Your Airtable API Key\n\n1. Go to [Airtable](https://airtable.com/).\n2. Log in or create a free account.\n3. Navigate to [**Developer Hub**](https://airtable.com/create/tokens) from your account menu.\n4. Under **Personal access tokens**, click **Create token**.\n5. Add the appropriate scopes (e.g. `data.records:read` and `data.records:write`).\n6. Copy your API token.\n   * Example: `patxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n\n1. Click the **Settings** gear icon and navigate to the **Integrations** tab.\n2. Find and enable the **Airtable** integration.\n3. Paste your **API Key** in the input field.\n4. Click **Connect** to confirm the connection.\n\n## Step 3: Use in Your Workflows\n\nOnce connected, you can use Airtable actions in your app to:\n\n* Fetch records to display dynamic lists\n* Add user submissions as new rows\n* Update status fields or metrics from AI workflows\n\nand more.\n\n","packages/integrations-docs/src/integrations_docs/docs/anthropic.md":"---\ntags: AI\ndescription: Connect your apps to Anthropic's Claude models for advanced AI capabilities.\n---\n# Anthropic Integration\n\nThe **Anthropic Integration** allows your app to use [Anthropic’s Claude models](https://www.anthropic.com/claude) for tasks such as text generation, summarization, reasoning, and other advanced AI capabilities. Once connected, you can call Claude directly from your workflows, UI actions, or automated triggers.\n\n\n## Step 1: Obtain an Anthropic API Key\n\n1. Go to the [Anthropic Console](https://console.anthropic.com/).\n2. Navigate to **API Keys** in your account settings.\n3. Click **Create Key** and give it a descriptive name (e.g., “AI Builder”).\n4. Copy the generated key.\n\n   * **Example:** `sk-ant-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Anthropic** in your app settings.\n2. Paste your **Anthropic API Key** in the input field.\n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Claude for AI-powered features across workflows and components.\n\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Anthropic API key in public code repositories.\n* **Use environment-specific keys:** Separate dev, staging, and production keys help manage access and security.\n* **Secure API access:** The key allows your app to interact with Anthropic endpoints securely and efficiently.\n\n\n","packages/integrations-docs/src/integrations_docs/docs/aws.md":"---\ntags: Data Infrastructure\ndescription: Connect to Amazon Web Services (AWS) for cloud storage, databases, compute, AI/ML, and more.\n---\n# AWS Integration\n\nThe **AWS Integration** allows your app to connect to [Amazon Web Services (AWS)](https://aws.amazon.com/) — the world's most comprehensive cloud platform. Once connected, your app can access 200+ AWS services including storage, databases, compute, AI/ML, and more using the boto3 SDK.\n\n## What You Can Do\n\nWith AWS integration, your app can:\n- **S3 (Object Storage):** Upload, download, and manage files in S3 buckets. Generate presigned URLs for secure file access. Works with S3-compatible services like MinIO, Cloudflare R2, and DigitalOcean Spaces.\n- **DynamoDB (NoSQL Database):** Store and query data in a fully managed, serverless NoSQL database with single-digit millisecond performance.\n- **Lambda (Serverless Functions):** Invoke serverless functions, run code without managing servers, and build event-driven applications.\n- **SES (Email Service):** Send transactional emails, marketing emails, and notifications with high deliverability.\n- **SNS (Notifications):** Send push notifications, SMS, and email messages to users across multiple channels.\n- **SQS (Message Queues):** Build distributed, decoupled systems with reliable message queuing.\n- **Rekognition (Computer Vision):** Analyze images and videos for object detection, facial analysis, text extraction, and content moderation.\n- **Comprehend (NLP):** Extract insights from text using natural language processing for sentiment analysis, entity recognition, and topic modeling.\n- **Bedrock (AI Models):** Access foundation models from AI21 Labs, Anthropic, Cohere, Meta, Stability AI, and Amazon for generative AI applications.\n- **And 200+ more services:** EC2, RDS, CloudWatch, Polly, Textract, Translate, and many others.\n\n## Step 1: Obtain AWS Credentials\n\n1. Log in to the [AWS Console](https://console.aws.amazon.com/).\n\n2. **Create IAM credentials:**\n   - Navigate to **IAM (Identity and Access Management)**.\n   - Click **Users** → **Add user** or select an existing user.\n   - Attach policies based on the AWS services you plan to use:\n     - **S3:** `AmazonS3FullAccess` or custom S3 policy\n     - **DynamoDB:** `AmazonDynamoDBFullAccess` or custom DynamoDB policy\n     - **Lambda:** `AWSLambdaFullAccess` or custom Lambda policy\n     - **SES:** `AmazonSESFullAccess` or custom SES policy\n     - **Multiple services:** Attach multiple policies or create a custom policy combining permissions\n\n   **Example custom policy for S3 + DynamoDB:**\n   ```json\n   {\n     \"Version\": \"2012-10-17\",\n     \"Statement\": [\n       {\n         \"Effect\": \"Allow\",\n         \"Action\": [\n           \"s3:PutObject\", \"s3:GetObject\", \"s3:DeleteObject\", \"s3:ListBucket\",\n           \"dynamodb:PutItem\", \"dynamodb:GetItem\", \"dynamodb:Query\", \"dynamodb:Scan\"\n         ],\n         \"Resource\": [\n           \"arn:aws:s3:::YOUR_BUCKET_NAME/*\",\n           \"arn:aws:dynamodb:YOUR_REGION:YOUR_ACCOUNT_ID:table/*\"\n         ]\n       }\n     ]\n   }\n   ```\n\n3. **Generate access keys:**\n   - Under **Security credentials**, click **Create access key**.\n   - Choose **Application running outside AWS** as the use case.\n   - Copy your **Access Key ID** and **Secret Access Key**.\n\n   **Example credentials:**\n   * **Access Key ID:** `AKIAIOSFODNN7EXAMPLE`\n   * **Secret Access Key:** `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add AWS** in your app settings.\n2. Enter your **AWS Access Key ID** and **AWS Secret Access Key**.\n3. **(Optional)** Select your **AWS Region** (e.g., `us-east-1`, `eu-west-1`). Defaults to `us-east-1`.\n4. **(Optional)** Enter an **AWS Endpoint URL** if using S3-compatible services:\n   - **MinIO:** `http://localhost:9000` or your MinIO server URL\n   - **Cloudflare R2:** `https://<account-id>.r2.cloudflarestorage.com`\n   - **DigitalOcean Spaces:** `https://<region>.digitaloceanspaces.com`\n   - Leave blank for standard AWS services.\n5. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can access AWS services using boto3.\n\n## Important Notes\n\n* **IAM permissions:** Ensure your IAM user has the necessary permissions for the AWS services you plan to use. Attach service-specific policies (e.g., `AmazonS3FullAccess`, `AmazonDynamoDBFullAccess`, `AWSLambdaFullAccess`) or create custom policies with least-privilege access.\n* **AWS Region:** Most AWS services are region-specific. Select the correct region where your resources are located (e.g., S3 buckets, DynamoDB tables, Lambda functions).\n* **Cost management:** Monitor AWS usage and costs through the AWS Billing Dashboard. Set up billing alerts to avoid unexpected charges.\n* **Security:** Rotate your access keys regularly and enable MFA for AWS console access. Apply least-privilege IAM policies to limit permissions to only what's needed.\n* **S3-compatible services:** For S3 operations, this integration works with S3-compatible storage like MinIO (self-hosted), Cloudflare R2 (zero egress fees), and DigitalOcean Spaces. Just provide the custom endpoint URL in the configuration.\n* **Service availability:** Not all AWS services are available in all regions. Check the [AWS Regional Services List](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/) for service availability.\n","packages/integrations-docs/src/integrations_docs/docs/azure_auth.md":"---\ntags: Authentication\ndescription: Integrate Azure for secure authentication and access management within your application.\n---\n# Azure Auth Manager Integration\n\nThe **Azure Auth Manager Integration** allows your app to authenticate users through Microsoft Azure Active Directory (Azure AD). This integration provides secure OAuth 2.0 authentication and supports multi-tenant applications with customizable tenant access.\n\n## Step 1: Set Up Azure App Registration\n\nBefore connecting, you need to register your app in Azure Portal:\n\n1 - Go to [Azure Portal](https://portal.azure.com) → **App Registrations**\n\n2 - Click **New registration** as shown in the image below:\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_1.webp)\n\n3 - Register your app. Ensure that for the Redirect URI you select **Web** and enter the following URI that you find in the Azure Auth Manager integration settings in AI Builder:\n   ```\n   https://{your-sandbox}/authorization-code/callback\n   ```\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_2.webp)\n\n4 - On the next page get your `client_id` (`AZURE_CLIENT_ID`) and `tenant_id` (`AZURE_VALID_TENANT_IDS`) from the **Overview** tab.\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_3.webp)\n\n5 - Next click `Add a certificate or secret` and copy the generated secret value (`AZURE_CLIENT_SECRET`).\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_4.webp)\n\n\n## Step 2: Configure the Integration\n\n1. Go to the **Integrations** section in your app settings by clicking **`@`** and then clicking the **Integrations** tab at the top.\n2. Click **Add** next to Azure Auth Manager.\n3. Fill in the credential fields:\n   - Enter your Azure Client ID\n   - Enter your Azure Client Secret\n   - Enter valid tenant IDs (comma-separated for multiple tenants)\n4. Click **Connect** to save the integration.\n\nYour app can now authenticate users through Azure AD with secure OAuth 2.0 flow.\n","packages/integrations-docs/src/integrations_docs/docs/cartesia.md":"---\ntags: AI\ndescription: Add Cartesia’s powerful text-to-speech capabilities for realistic, real-time voice output and audio experiences.\n---\n# Cartesia Integration\n\nThe **Cartesia Integration** allows your app to generate **high-quality, realistic speech from text** using Cartesia’s advanced voice models. Once connected, you can easily add real-time voice capabilities to workflows, user interactions, and automated experiences.\n\n\n## Step 1: Obtain a Cartesia API Key\n\n1. Go to the [Cartesia Console](https://www.cartesia.ai/).  \n2. Log in or create an account.  \n3. Navigate to **API Keys** in your account settings.  \n4. Click **New**, give it a descriptive name (e.g., “AI Builder”), and copy it.  \n   - Example: `sk_car_xxxxxxxxxxxxx`\n\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Open your app and go to **Integrations → Add Cartesia**.  \n2. Paste your **Cartesia API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.  \n\nOnce connected, your app can convert text to speech seamlessly in real time or through workflows.\n\n\n\n## Step 3: Notes\n\n- **Secure API Access:** Keep your Cartesia API key safe. Do not hardcode it in public code.  \n- **Environment isolation:** Use different keys for dev, staging, and production to ensure clean separation.  \n- **Low latency:** Cartesia supports real-time streaming for conversational experiences.  \n- **Usage management:** Monitor your Cartesia dashboard for quotas, billing, and usage insights.\n\n","packages/integrations-docs/src/integrations_docs/docs/cohere.md":"---\ntags: AI\ndescription: Add Cohere’s language models for text generation, classification, retrieval, embeddings, and more.\n---\n# Cohere Integration\n\nThe **Cohere Integration** allows your app to use [Cohere’s](https://cohere.com) state-of-the-art language models for natural language understanding and generation. Once connected, your app can power search, summarization, embeddings, classification, and conversational AI features directly from workflows and triggers.\n\n\n## Step 1: Obtain a Cohere API Key\n\n1. Go to the [Cohere Dashboard](https://dashboard.cohere.com/).  \n2. Log in or create an account.  \n3. Navigate to **API Keys** in your account settings.  \n4. Click **Create Key**, give it a descriptive name (e.g., “AI Builder”), and copy the key.  \n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Cohere** in your app settings.  \n2. Paste your **Cohere API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.  \n\nOnce connected, your app can access Cohere’s endpoints for language tasks like embeddings, classification, chat, and more.\n\n\n## Step 3: Notes\n\n- **Secure API Access:** Keep your Cohere API key private — do not hardcode it in public repositories.  \n- **Environment separation:** Use different keys for development, staging, and production environments.  \n- **Performance:** Cohere’s models support fast inference for production-ready experiences.  \n- **Observability:** Use the Cohere dashboard to monitor usage, quotas, and request logs.\n\n","packages/integrations-docs/src/integrations_docs/docs/database.md":"---\ntags: Data Infrastructure\ndescription: Connect Reflex Build apps to PostgreSQL, MySQL, MSSQL, or SQLite databases.\n---\n# Database Integration\n\nThe Database Integration connects Reflex Build apps to an existing SQL database. When you enable the connection for an app, Reflex Build can inspect its schema and use that structure while generating the app.\n\n## Supported Databases\n\n- **PostgreSQL**\n- **MySQL**\n- **MSSQL** (Microsoft SQL Server)\n- **SQLite**\n\n## Add a Database Integration\n\n1. Open **Integrations** from the project sidebar.\n2. Select **Add Integration**.\n3. Search for and select **Database**.\n4. Configure the connection using **Connection Details** or **Database URI**.\n5. Optionally enter an integration name to distinguish this connection from others in the project.\n6. Select **Save Changes**.\n\nThe integration is saved at the project level. Open an app's **Integrations** panel to enable it for that app when needed.\n\n## Connection Details\n\nUse **Connection Details** to enter each part of the connection separately.\n\nFor PostgreSQL, MySQL, and MSSQL, choose the database type and enter:\n\n- `hostname`: the database server address.\n- `port`: defaults to `5432` for PostgreSQL, `3306` for MySQL, or `1433` for MSSQL.\n- `username` and `password`: the database credentials.\n- `database_name`: the database to connect to.\n\nFor MSSQL, **Trust Server Certificate** skips certificate identity validation. Use it only as a temporary workaround for an untrusted or self-signed server certificate, and prefer configuring a certificate that the client trusts.\n\nFor SQLite, select **SQLite** and enter an HTTP or HTTPS **SQLite Download URL**. Reflex Build downloads the database file before using it.\n\n## Database URI\n\nUse **Database URI** when you have a complete connection URI for one of the supported database types. For example:\n\n```text\npostgresql://username:password@hostname:5432/database_name\n```\n\nEnter the URI in `db_url`, then select **Save Changes**. Reflex Build selects the database driver automatically. Include provider-required connection options as query parameters when needed.\n\n## Connect through an SSH Tunnel\n\nUse an SSH tunnel when the database is on a private network but can be reached through a bastion host. This option is available for PostgreSQL, MySQL, and MSSQL in both connection modes. It is not available for SQLite.\n\n1. Enter the database connection details or URI. Keep the database hostname and port set to the address the bastion host uses to reach the database.\n2. Turn on **Connect via SSH tunnel**.\n3. Enter the `ssh_hostname`, `ssh_port` (usually `22`), and `ssh_username` for the bastion host.\n4. Paste the corresponding PEM-formatted **SSH private key**.\n5. Select **Save Changes**.\n\nThe SSH account must allow port forwarding to the database host and port. Use a dedicated, restricted SSH key and database user for Reflex Build.\n\n```md alert warning\n# Keep credentials private\n\nEnter database passwords, connection URIs, and SSH private keys only in the integration form. Do not put them in prompts, knowledge, source code, or screenshots.\n```\n\n## Enable the Integration for an App\n\nOpen the app's **Integrations** panel and enable the saved database connection. Reflex Build then connects to the database and, when the app does not already have a model file, creates the app's data models from the schema.\n\nIf the connection fails, check that:\n\n- The database or bastion host is reachable.\n- The ports are open and the credentials are valid.\n- The database user can read the schema and has only the data permissions the app needs.\n- The SSH user can forward traffic to the database when tunneling is enabled.\n\n```md alert\n# NoSQL Databases\n\nUse the dedicated MongoDB integration when applicable. For another NoSQL database, add its Python SDK or configure a custom integration; the Database Integration supports SQL databases.\n```\n","packages/integrations-docs/src/integrations_docs/docs/databricks.md":"---\ntags: Data Infrastructure\ndescription: Connect with Databricks to run data pipelines and advanced analytics seamlessly.\n---\n\n\n# Databricks Integration\n\nThe **Databricks Integration** allows your app to connect to [Databricks](https://www.databricks.com/) for secure data access, querying, and analytics. Once connected, you can run SQL queries, retrieve results, and power data-driven workflows directly from your app.\n\n## What You Can Do\n\nWith Databricks, your app can:\n- Connect securely to your Databricks workspace.  \n- Run **SQL queries** or fetch data programmatically.  \n- Build **dashboards and data visualizations** on top of your Databricks tables.  \n- Automate workflows triggered by new or updated data.  \n- Combine Databricks with AI models for advanced analytics.\n\n\n\n## Step 1: Get Your Databricks Credentials\n\n### 1 - Log in to your [Databricks Workspace](https://databricks.com/).\n\n### 2 - Get your **DATABRICKS_HOST** and **DATABRICKS_WAREHOUSE_ID**:\n\n   - Go to `SQL Warehouses` from the sidebar.\n   - Select your desired warehouse.\n   - Click `Connection details`.\n   - Copy the Server hostname (this is your **DATABRICKS_HOST**).\n   - Copy the HTTP path removing the `/sql/1.0/warehouses/` prefix (this is your **DATABRICKS_WAREHOUSE_ID**).\n\n![Databricks SQL Warehouse connection details](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_1.webp)\n\n### 3 - Get your **DATABRICKS_CATALOG** and **DATABRICKS_SCHEMA**:\n   - Click the SQL Editor from the sidebar.\n   - Choose the **DATABRICKS_CATALOG** and **DATABRICKS_SCHEMA** from the dropdowns as shown below.\n\n![Selecting Databricks catalog and schema in SQL Editor](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_4.webp)\n\n\n### 4 - Obtain your authentication credentials:\n\nThere are two methods to authenticate your app with Databricks: using interactive U2M **OAuth** or via registered M2M **Service Principal**. Choose one of the methods below to obtain the necessary credentials.\n\n\n`````md tabs\n\n## OAuth with Databricks\n\n#### Interactive Login with your Databricks Account\n\nIf your workspace administrator has already added Reflex as a Connected App in your Databricks workspace, you should see a \"Login with Databricks\" button after entering your DATABRICKS_HOST.\n\n\n## Service Principal\n\n#### M2M Service Principal (DATABRICKS_CLIENT_ID and DATABRICKS_CLIENT_SECRET)\n\n- Open the dropdown in the top right corner and select **Manage Account**.\n\n![Opening Manage Account in Databricks](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_1.webp)\n\n- Select `Users and Groups`\n\n![Selecting Users and Groups in Databricks account](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_2.webp)\n\n- Select the `Service Principals` tab and click `Add Service Principal`.\n\n![Adding a Databricks service principal](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_3.webp)\n\n- Fill in the details and click `Add Service Principal`.\n\n![Entering Databricks service principal details](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_4.webp)\n\n- Click the `Credentials and Secrets` tab and click `Generate Secret`.\n\n![Generating a Databricks service principal secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_5.webp)\n\n- Set a lifetime for the secrets and click `Generate`.\n\n![Setting Databricks secret lifetime](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_6.webp)\n\n- Copy the generated **DATABRICKS_CLIENT_ID** and **DATABRICKS_CLIENT_SECRET**.\n\n![Copying Databricks client ID and secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_7.webp)\n\n`````\n\n\n\n## Step 2: Configure the Integration in Your App\n\n1. In your app, go to **Integrations** and **Add Databricks**.\n2. Paste your **DATABRICKS_HOST**\n3. Select your authentication method:\n   - OAuth, if configured.\n   - Service Principal, provide the client ID and secret gathered previously.\n2. Paste or select your\n   1. **DATABRICKS_WAREHOUSE_ID**\n   2. **DATABRICKS_CATALOG**\n   3. **DATABRICKS_SCHEMA**  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, the AI Builder can execute queries directly against your Databricks environment.\n\n\n## Step 3: Notes\n\n* **Secure your token:** Never expose tokens in public code.  \n* **Permissions:** Ensure your token or service account has the required workspace and table permissions.\n* **Combine with AI:** Use query outputs to power models, summaries, or alerts in real time.\n\n\n## How to Enable Login as an Admin\n\n- Login to Databricks\n- Go to manage account\n\n![Opening Manage Account as Databricks admin](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_admin_auth_1.webp)\n\n- Go to **Settings** → **Apps Connections** → **Add new connection**\n\n![Adding a new app connection in Databricks settings](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_admin_auth_2.webp)\n\n- Give it a name, enter the redirect URL that Reflex Build provides, Click `All APIs` and uncheck `Generate a client secret` and then add.\n   - URL: `https://build.reflex.dev/_reflex_oidc_databricks/authorization-code/callback`\n\n![Configuring the Reflex redirect URL in Databricks](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_admin_auth_3.webp)","packages/integrations-docs/src/integrations_docs/docs/descope.md":"---\ntags: Authentication\ndescription: Add Descope’s identity and authentication platform to your apps to manage user sign-in, onboarding, MFA, SSO, and flows with ease.\n---\n# Descope Integration\n\nThe **Descope Integration** enables your app to leverage Descope’s full Customer Identity & Access Management (CIAM) features—visual authentication flows, identity management, SSO, MFA, tenant isolation, and more. Once set up, you can orchestrate secure user journeys across your application with minimal coding.\n\n\n```md alert warning\n# You must open your app in a new tab from the builder to test the Descope integration.\n```\n\n## What You Can Do\n\nWith Descope Integration, your app can:\n- Handle user sign-up, login, and passwordless flows seamlessly  \n- Enable multifactor authentication (MFA), passkeys, and social login  \n- Support single sign-on (SSO) via OIDC/SAML  \n- Manage users, roles, tenants, and permissions via management APIs  \n- Orchestrate onboarding, branding, and multi-tenant flows via drag-and-drop workflows  \n- Sync user data with tools like HubSpot or Segment via built-in connectors\n\n\n## Step 1: Obtain Descope Credentials\n\n![Descope Credentials](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/descope.webp)\n\n1. Log in to the [**Descope Console** (or sign up)](https://www.descope.com/sign-up).\n2. Create your first Project. \n3. Go to the Project page under Settings.\n4. Copy the `Project ID`.\n\n\n## Step 2: Configure the Integration in Your App\n\n1. In your app’s settings or integration dashboard, select **Add Descope**.  \n2. Enter your **PROJECT_ID**.  \n3. (Optional) Pick a **DESCOPE_FLOW_ID** (e.g. “sign-up-or-login”) and **SESSION_SECRET_KEY** or press the Clipboard Copy to use default values.  \n4. Click **Connect** to validate credentials and enable Descope features.\n\n![Descope Integration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/descope_2.webp)\n\n\n","packages/integrations-docs/src/integrations_docs/docs/gemini.md":"---\ntags: AI\ndescription: Connect your apps to Google’s Gemini models for advanced AI capabilities.\n---\n# Gemini Integration\n\nThe **Gemini Integration** allows your app to use [Google’s Gemini models](https://aistudio.google.com/) for text generation, reasoning, multimodal analysis, and other advanced AI capabilities. Once connected, you can call Gemini directly from your workflows, UI actions, or automated triggers.\n\n## Step 1: Obtain a Gemini API Key\n\n1. Go to [Google AI Studio](https://aistudio.google.com/).\n2. Navigate to **Get API Key** or create a new key for your project.\n3. Copy the generated key.\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Gemini** in your app settings.  \n2. Paste your **Gemini API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Gemini for AI-powered features across workflows and components.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Gemini API key in public code repositories.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys help manage access and security.  \n* **Secure API access:** The key allows your app to interact with Gemini endpoints securely and efficiently.\n","packages/integrations-docs/src/integrations_docs/docs/github.md":"---\ntags: Developer Tools\ndescription: Connect your app to GitHub to automate workflows, manage repositories, and integrate developer operations.\n---\n# GitHub Integration\n\nThe **GitHub Integration** lets your app connect directly to [GitHub](https://github.com) to automate actions, fetch data, and build powerful developer workflows. Once connected, your app can interact with repositories, issues, pull requests, and more.\n\n## What You Can Do\n\nWith GitHub, your app can:\n- Fetch and display repository data (commits, branches, issues, etc.).  \n- Create or update issues, pull requests, and discussions.  \n- Trigger workflows or CI/CD pipelines.  \n- Sync GitHub activity into your app’s dashboards or automations.  \n- Build custom developer tools using GitHub’s API.\n\n## Step 1: Generate a Personal Access Token\n\n1. Go to your [GitHub Settings](https://github.com/settings/tokens).  \n2. Navigate to **Developer settings → Personal access tokens**.  \n3. Click **Generate new token** (classic or fine-grained).  \n4. Select the required scopes (e.g., `repo`, `workflow`, `read:user`).  \n5. Copy the token.  \n   **Example token:**  \n```\nghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n```\n(Note: Replace the above value with your actual GitHub token)\n\n> 💡 Fine-grained tokens are recommended for better security.\n\n## Step 2: Configure the Integration in Your App\n\n1. In your app, go to **Integrations → Add GitHub**.  \n2. Paste your **GitHub Personal Access Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can start interacting with GitHub through workflows and actions.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Never expose your GitHub token in public code.  \n* **Use fine-grained permissions:** Limit access to only what’s needed.  \n* **API rate limits:** GitHub imposes API limits, so plan automations accordingly.  \n* **Combine with AI:** For example, auto-generate release notes from commits or summarize PRs with LLMs.\n\n","packages/integrations-docs/src/integrations_docs/docs/google_auth.md":"---\ntags: Authentication\ndescription: Enable secure authentication using Google sign-in and OAuth 2.0 workflows.\n---\n\n# Google Auth Integration\n\nThe **Google Auth Integration** allows your app to authenticate users using their Google accounts. This provides a secure, familiar login experience and simplifies user management.\n\n\n## Step 1: Create a Google OAuth Client\n\n1 - Go to the [Google Cloud Console](https://console.cloud.google.com/)\n\n2 - Navigate to **APIs & Services → Credentials**\n\n3 - Click **Create Credentials**\n\n![Creating credentials in Google Cloud Console](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_1.webp)\n\n4 - Choose **OAuth client ID**.\n\n![Choosing OAuth client ID credential type](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_2.webp)\n\n5 - Choose **Web Application** as the application type, name the application and enter your sandbox URL, which you get from the Google Auth integration panel, as the **Authorized JavaScript Origin** and **Authorized Redirect URIs**.\n\n![Configuring Google OAuth web application origins](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_3.webp)\n\n6 - Copy the generated **Client ID** (`GOOGLE_CLIENT_ID`) and **Client Secret** (`GOOGLE_CLIENT_SECRET`).\n\n![Copying Google client ID and secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_4.webp)\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Google Auth** in your app settings.\n2. Enter your **Google Client ID** and **Google Client Secret**.\n3. Save the integration. Your app is now configured to use Google Auth for login.\n\n## Step 3: Notes\n\n- The integration supports multiple environments (development, staging, production). Use environment-specific secrets for the client ID and secret.\n- Google Auth handles token refresh automatically when users log in via OAuth.\n- Users will see a standard Google login screen, ensuring familiarity and trust.\n- Ensure your app domain matches the authorized JavaScript origin and redirect URIs; otherwise, authentication will fail.\n","packages/integrations-docs/src/integrations_docs/docs/groq.md":"---\ntags: AI\ndescription: Connect your apps to Groq’s ultra-fast inference API for lightning-speed AI responses.\n---\n# Groq Integration\n\nThe **Groq Integration** allows your app to use [Groq’s API](https://groq.com/) for ultra-fast AI inference. Once connected, your app can leverage Groq’s hosted models (including open models like Llama 4 and Qwen) to power real-time workflows, chat experiences, and other AI-driven features.\n\n## Step 1: Obtain a Groq API Key\n\n1. Go to the [Groq Console](https://console.groq.com/).  \n2. Navigate to **API Keys** in your account settings.  \n3. Click **Create API Key** and give it a descriptive name (e.g., “AI Builder”).  \n4. Copy the generated key.\n   * **Example:** `gsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Groq** in your app settings.  \n2. Paste your **Groq API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Groq to deliver ultra-low latency AI responses across workflows and components.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Groq API key in public code repositories.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys help manage access and security.  \n* **Secure API access:** The key allows your app to interact with Groq endpoints securely and efficiently.\n","packages/integrations-docs/src/integrations_docs/docs/hubspot.md":"---\ntags: Data Infrastructure\ndescription: Connect your apps to HubSpot to manage contacts, companies, deals, and marketing workflows.\n---\n# HubSpot Integration\n\nThe **HubSpot Integration** allows your app to use [HubSpot](https://www.hubspot.com/) as a CRM and marketing automation platform. Once connected, your app can sync leads, manage contacts, update pipelines, and trigger workflows directly from user actions or automated events.\n\n## Step 1: Obtain a HubSpot Access Token\n\n1. Go to your [HubSpot Developer Account](https://developers.hubspot.com/).  \n2. Navigate to **App → Private Apps** in your account settings.  \n3. Click **Create Private App**, configure scopes (e.g., `crm.objects.contacts.read/write`, `crm.schemas.companies.read`), and save.  \n4. Copy the **Access Token** from the Auth tab.\n   * **Example:** `pat-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add HubSpot** in your app settings.  \n2. Paste your **HubSpot Access Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can sync and manage HubSpot data directly from workflows and UI actions.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Do not hardcode your HubSpot token in public code repositories.  \n* **Use environment-specific tokens:** Separate dev, staging, and production tokens to manage access.  \n* **Secure API access:** The token allows your app to interact with HubSpot endpoints securely and efficiently.\n\n","packages/integrations-docs/src/integrations_docs/docs/hugging_face.md":"---\ntags: AI\ndescription: Connect your apps to Hugging Face to access thousands of open models for text, vision, and multimodal tasks.\n---\n# Hugging Face Integration\n\nThe **Hugging Face Integration** allows your app to use [Hugging Face](https://huggingface.co/) models for a wide range of AI tasks — including text generation, embeddings, translation, classification, image processing, and more. You can integrate both hosted models (via API) or local open-source models through the Transformers library.\n\n## What You Can Do\n\nWith Hugging Face, your app can:\n- Access thousands of pre-trained **text, vision, and multimodal models**.  \n- Run **text generation**, summarization, translation, and classification tasks.  \n- Use **embeddings** for search, retrieval, and similarity.  \n- Deploy models locally with `transformers` or connect to hosted inference endpoints.  \n- Fine-tune or customize open models for your specific use cases.  \n- Integrate community and enterprise models seamlessly into workflows.\n\n## Step 1: Obtain a Hugging Face Access Token (Optional)\n\n1. Go to [Hugging Face](https://huggingface.co/).  \n2. Log in or create a free account.  \n3. Navigate to **Settings → Access Tokens**.  \n4. Click **Create New token**, set its scope, and copy it.\n   * **Example:** `hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Hugging Face** in your app settings.  \n2. Paste your **Hugging Face Access Token** if required.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Hugging Face models directly in workflows, UI actions, or automations.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Never expose your Hugging Face token in client-side code.  \n* **Use environment-specific tokens:** Separate dev, staging, and production access.  \n* **Open-source flexibility:** Models can be run fully locally or through Hugging Face’s hosted endpoints.  \n* **Broad ecosystem:** Hugging Face supports thousands of community and commercial models for rapid prototyping and production use.\n","packages/integrations-docs/src/integrations_docs/docs/langchain.md":"---\ntags: AI\ndescription: Connect your apps to Langchain for advanced AI capabilities.\n---\n# Langchain Integration\nThe **LangChain Integration** allows your app to leverage the power of [LangChain](https://langchain.com/), a popular open-source framework for building applications with large language models (LLMs). Once connected, your app can orchestrate complex AI workflows, chain together multiple model calls, and integrate with various data sources and tools seamlessly.\n\n\nYou can:\n\n* **Chain model calls together** to create multi-step reasoning flows.\n* **Connect multiple providers** (e.g., OpenAI, Anthropic, Gemini, Groq) through a single interface.\n* **Build intelligent agents** that can use tools, call APIs, or access external data sources dynamically.\n* **Work with structured data** by combining LLMs with databases, vector stores, and retrieval systems.\n* **Create RAG (Retrieval-Augmented Generation)** pipelines to ground model outputs in your own data.\n* **Integrate tools and memory** so models can reason over past interactions and context.\n* **Deploy reusable components** like prompt templates, chains, and agents for production-grade applications.\n\nLangChain essentially acts as a **“glue layer”** between language models, data, and logic — enabling teams to build more **powerful and reliable AI apps** without reinventing core orchestration features.\n\n\n## Configure the Integration in Your App\n\n1. Click the **Settings** gear icon and navigate to the **Integrations** tab.\n2. Find and enable the **LangChain** integration.\n\n","packages/integrations-docs/src/integrations_docs/docs/linear.md":"---\ntags: DevTools\ndescription: Connect your apps to Linear to manage issues, projects, and sprints directly from workflows.\n---\n# Linear Integration\n\nThe **Linear Integration** allows your app to connect to [Linear](https://linear.app/) to create, update, and track issues and projects seamlessly. Once connected, your app can trigger Linear actions from user interactions or automated workflows.\n\n## What You Can Do\n\nWith Linear, your app can:\n- **Create and assign issues** automatically from user actions or AI workflows.  \n- **Update status and priority** of tickets and projects.  \n- **Sync with sprints and cycles** to keep work organized.  \n- **Fetch project and issue data** for dashboards, summaries, or automation.  \n- **Integrate with other tools** like Slack or GitHub through workflows.  \n- Power intelligent workflows (e.g., auto-triage or auto-summarize bug reports).\n\n## Step 1: Obtain a Linear API Key\n\n1. Go to your [Linear account](https://linear.app/).  \n2. Navigate to **Workspace Settings → API**.  \n3. Click **Create API Key**, give it a name, and copy the key.\n\n   * **Example:** `lin_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Linear** in your app settings.\n2. Paste your **Linear API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can interact with Linear to automate issue tracking and project management.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Never expose your Linear API key in client-side code.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys.  \n* **Streamlined workflows:** Automate ticket creation, status updates, and reporting directly from your app.  \n* **Real-time visibility:** Fetch and sync project data to power internal tools or dashboards.\n\n","packages/integrations-docs/src/integrations_docs/docs/notion.md":"---\ntags: Data Infrastructure\ndescription: Connect your apps to Notion to create, update, and query pages, databases, and documents.\n---\n# Notion Integration\n\nThe **Notion Integration** allows your app to connect to [Notion](https://www.notion.so/) to manage content, automate workflows, and build dynamic interfaces on top of Notion workspaces. Once connected, your app can read and write pages, sync databases, and trigger actions based on user activity.\n\n## What You Can Do\n\nWith Notion, your app can:\n- **Create and update pages** in workspaces automatically.  \n- **Read and query databases** to power dashboards, workflows, or automations.  \n- **Sync structured content** like tasks, notes, or documentation with other tools.  \n- Trigger **actions from AI workflows** (e.g., creating meeting notes, logging issues).  \n- Integrate with other services (e.g., Slack, Linear, HubSpot) for seamless collaboration.\n\n## Step 1: Obtain a Notion API Token\n\n1. Go to the [Notion Developers](https://www.notion.so/my-integrations) page.  \n2. Click **+ New Integration**, give it a name, and copy the generated **Internal Integration Token**.  \n3. Share the integration with the relevant pages or databases in your workspace to grant access.\n\n   * **Example:** `ntn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Notion** in your app settings.  \n2. Paste your **Notion API Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can read and write to Notion directly from workflows and UI actions.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Never expose your Notion token in client-side code.  \n* **Use environment-specific tokens:** Separate dev, staging, and production access.  \n* **Granular permissions:** Only share the integration with the pages or databases it needs to access.  \n* **Powerful building block:** Use Notion as a single source of truth for content, tasks, or structured data.\n\n","packages/integrations-docs/src/integrations_docs/docs/okta_auth.md":"---\ntags: Authentication\ndescription: Use Okta for secure identity and access management via Single Sign-On provisioning.\n---\n\n# Okta Auth Manager Integration\n\nThe **Okta Auth Manager Integration** allows your app to authenticate users through [Okta](https://okta.com). This integration provides secure OAuth 2.0 / OIDC authentication and supports multi-tenant environments with customizable access policies.\n\n\n## What You Can Do\n\nWith Okta, your app can:\n- Authenticate users securely through Okta’s identity platform.  \n- Enable **SSO** for enterprise users.  \n- Manage user roles, groups, and access permissions.  \n- Protect sensitive data and actions with **OAuth 2.0** and **OpenID Connect (OIDC)**.  \n- Integrate with other identity workflows like MFA or adaptive policies.\n\n\n## Step 1: Set Up Okta OIDC App\n\nBefore connecting, you need to create an OIDC application in the Okta Admin Console:\n\n1 - Go to [Okta Admin Console](https://login.okta.com) → **Applications** → **Applications**\n\n\n2 - Click **Create App Integration**\n\n![Creating an Okta app integration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_1.png)\n\n3 - Select **OIDC – OpenID Connect** and choose **Web Application**\n\n![Selecting OIDC web application in Okta](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_2.png)\n\n4 - Configure your app settings:\n   - **Allow wildcard * in sign-in redirect URIs**\n   - **Sign-in redirect URIs** found in the Okta Auth Manager integration settings in AI Builder:\n     `https://{your-sandbox}/authorization-code/callback`\n   - **Sign-out redirect URIs**:\n     `https://{your-sandbox}`\n   - Assign to the correct **Group** or **Everyone** depending on your access control\n\n![Configuring Okta sign-in redirect URIs](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_3.png)\n\n5 - Save the app integration.\n\n6 - Copy your **Client ID** (`OKTA_CLIENT_ID`) and **Client Secret** (`OKTA_CLIENT_SECRET`) from the app settings.\n\n![Copying Okta client ID and secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_4.png)\n\n\n## Step 2: Finding Your Okta Issuer URI\n\n1. In the Okta Admin Console, go to **Security** → **API** → **Authorization Servers**\n2. Click on the **default** server and copy the **Issuer URI**.\n3. Remove the trailing `/oauth2/default` from the URI to get your **Okta Issuer URI** (`OKTA_ISSUER_URI`).\n\nExample:\n\nIf your Issuer URI is `https://{yourOktaDomain}.okta.com/oauth2/default`\n\nUse `https://{yourOktaDomain}.okta.com`\n\n![Finding the Okta issuer URI](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_5.png)\n\n\n> **Note:** Always use separate Okta apps for dev, staging, and production environments to avoid mixing credentials.\n\n\n## Step 3: Configure the Integration\n\n1. Go to the **Integrations** section in your app settings by clicking **`@`** and then selecting the **Integrations** tab.\n2. Click **Add** next to **Okta Auth Manager**.\n3. Fill in the credential fields:\n   - Enter your Okta Client ID\n   - Enter your Okta Client Secret\n   - Enter your Okta Issuer URI\n4. Click **Connect** to save the integration.\n\nYour app can now authenticate users through Okta using the secure OAuth 2.0 / OIDC flow.\n","packages/integrations-docs/src/integrations_docs/docs/openai.md":"---\ntags: AI\ndescription: Connect to OpenAI's powerful language models for text generation, analysis, and more.\n---\n# OpenAI Integration\n\nThe **OpenAI Integration** allows your app to use OpenAI APIs for features such as text generation, embeddings, and other AI-powered functionality.\n\n## Step 1: Obtain an OpenAI API Key\n\n1. Go to the [OpenAI Platform](https://platform.openai.com/).\n2. Navigate to **API Keys** in your account settings.\n3. Click **Create new secret key**.\n4. Copy the generated key.\n   - Example: `sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add OpenAI Integration** in your app settings.\n2. Enter your **OpenAI API Key** in the input field.\n3. Save the integration. Your app is now ready to make OpenAI API requests.\n\n---\n\n## Step 3: Notes\n\n- Keep your OpenAI key secure; do **not** hardcode it in public code repositories.\n- Use environment-specific secrets if you have separate development, staging, and production environments.\n- The key allows your app to interact with OpenAI endpoints securely and efficiently.\n","packages/integrations-docs/src/integrations_docs/docs/overview.md":"```python exec\nfrom pcweb.pages.integrations.integration import integration_page\n```\n\n```python eval\nintegration_page()\n```\n","packages/integrations-docs/src/integrations_docs/docs/perplexity.md":"---\ntags: AI\ndescription: Connect your apps to Perplexity to power real-time, retrieval-augmented AI experiences.\n---\n# Perplexity Integration\n\nThe **Perplexity Integration** allows your app to use [Perplexity](https://www.perplexity.ai/) to deliver fast, accurate, retrieval-augmented answers from the web and trusted sources. Once connected, you can use Perplexity to enhance search, summarization, and real-time knowledge in your workflows.\n\n## What You Can Do\n\nWith Perplexity, your app can:\n- **Retrieve real-time information** from the web to ground model outputs.  \n- **Generate concise summaries** and answers with citations.  \n- Power **search experiences**, research assistants, and contextual AI features.  \n- **Combine Perplexity with other models** for hybrid workflows (e.g., retrieval + reasoning).  \n- Enable **trusted, source-backed outputs** for more accurate responses.\n\n## Step 1: Obtain a Perplexity API Key\n\n1. Go to the [Perplexity](https://www.perplexity.ai/).  \n2. Log in or create an account.  \n3. Navigate to **Account → API → [API Keys](https://www.perplexity.ai/account/api/keys)**.  \n4. Click **Generate Key** and copy the generated key.\n\n   * **Example:** `pplx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Perplexity** in your app settings.  \n2. Paste your **Perplexity API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Perplexity for retrieval-augmented AI features across workflows and components.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Perplexity API key in public code repositories.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys for better control.  \n* **Secure API access:** The key allows your app to interact with Perplexity endpoints securely and efficiently.  \n* **Real-time power:** Perplexity is ideal for use cases where freshness and factual grounding matter.\n","packages/integrations-docs/src/integrations_docs/docs/replicate.md":"---\ntags: AI\ndescription: Connect your apps to Replicate to run and deploy open-source machine learning models with ease.\n---\n# Replicate Integration\n\nThe **Replicate Integration** allows your app to use [Replicate](https://replicate.com/) to run open-source AI models in the cloud without managing infrastructure. Once connected, you can use Replicate to generate text, images, audio, and more — directly from workflows and UI actions.\n\n## What You Can Do\n\nWith Replicate, your app can:\n- Run open-source **AI models** without GPU or hosting setup.  \n- Access models for **text generation**, **image generation**, **audio**, and **multimodal tasks**.  \n- Automate workflows like content generation, data processing, or AI-powered features.  \n- Use prebuilt models or deploy your own custom models.  \n- Scale effortlessly with serverless infrastructure.\n\n## Step 1: Obtain a Replicate API Token\n\n1. Go to the [Replicate Dashboard](https://replicate.com/account).  \n2. Log in or create an account.\n3. Navigate to the **API Tokens** section.  \n4. Copy your **API Token** from the account page.\n\n   * **Example:** `r8_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Replicate** in your app settings.  \n2. Paste your **Replicate API Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can call Replicate models directly in workflows, UI actions, or automations.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Do not hardcode your Replicate token in public code repositories.  \n* **Use environment-specific tokens:** Separate dev, staging, and production environments for security.  \n* **Secure API access:** The token allows your app to interact with Replicate endpoints safely and efficiently.  \n* **Model flexibility:** You can use community models or deploy your own for full control.\n","packages/integrations-docs/src/integrations_docs/docs/resend.md":"---\ntags: Communication\ndescription: Send transactional and automated emails directly from your AI-generated applications using Resend.\n---\n# Resend Integration\n\nThe **Resend Integration** allows your AI-generated apps to send emails directly from workflows, user actions, or automated triggers — perfect for notifications, confirmations, or any email-based communication your app needs.\n\n\n## What You Can Do\n\nWith the Resend Integration, your app can:\n- Send automated transactional emails\n- Notify users of important events (signups, job completions, etc.)\n- Integrate email sending into AI workflows\n- Use dynamic variables in your message body (e.g. user name, order ID)\n\n## Step 1: Get Your Resend API Key\n\n1. Go to [Resend](https://resend.com/).\n2. Log in or create a free account.\n3. Navigate to **API Keys** from the dashboard sidebar.\n4. Click **Create API Key**, give it a name (e.g. “AI Builder”), and copy it.\n   - Example: `re_xxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Open your app in the **AI Builder**.\n2. Click the **Settings** gear icon and navigate to the **Integrations** tab.\n3. Find and enable the **Resend** integration.\n4. Paste your **API Key** in the input field.\n5. Click **Connect** to confirm the connection.\n","packages/integrations-docs/src/integrations_docs/docs/roboflow.md":"---\ntags: AI\ndescription: Connect your apps to Roboflow to use computer vision models and datasets for image detection, classification, and segmentation.\n---\n# Roboflow Integration\n\nThe **Roboflow Integration** allows your app to use [Roboflow](https://roboflow.com/) to run and deploy computer vision models without complex infrastructure. Once connected, you can use Roboflow to power image detection, object tracking, classification, and segmentation workflows.\n\n## What You Can Do\n\nWith Roboflow, your app can:\n- Run **pre-trained computer vision models** for detection, classification, or segmentation.  \n- Deploy and use **custom-trained models** built in Roboflow.  \n- Automate workflows that rely on visual inputs — e.g., quality checks, object detection, image analysis.  \n- Ingest and process **images in real time**.  \n- Combine vision outputs with other integrations (e.g., AI reasoning, automation flows).\n\n```md alert\n## This integration currently supports image inputs only.\nVideo and streaming inputs are not yet supported.\n```\n\n## Step 1: Obtain a Roboflow API Key\n\n1. Go to your [Roboflow Account](https://roboflow.com/).\n2. Navigate to **Settings → API Keys**.  \n3. Copy your Private API Key.\n\n\n## Step 2: Set up your Model in Roboflow\n\n1. Go to Workflows and create a new workflow.\n2. Set up the workflow you want to use in your app, ensuring that it takes an image as input.\n3. Click the `deploy` button, select `Images` and then select `Integrate with my app or website`.\n4. Copy the `workspace_name` and `workflow_id` from the provided code snippet.\n\n![Roboflow](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/roboflow.webp)\n\n## Step 3: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Roboflow** in your app settings.  \n2. Paste your **Roboflow API Key**, **Workspace Name**, and **Workflow ID** in the input fields.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can call Roboflow models directly from workflows, UI actions, or automated triggers.\n\n\n## Step 4: Notes\n\n* **Keep your key secure:** Never expose your Roboflow key in client-side code.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys to control access.  \n* **Model flexibility:** Use community models or your own custom-trained models.  \n* **Real-time vision:** Ideal for applications involving cameras, inspection, monitoring, or visual AI.\n","packages/integrations-docs/src/integrations_docs/docs/snowflake.md":"# Snowflake\n\nSnowflake is a cloud-based data warehousing platform that enables users to store, manage, and analyze large volumes of data. It provides a scalable and flexible architecture that separates storage and compute resources, allowing for efficient data processing and querying.\n\nThe integration supports two authentication methods: **OAuth** (each user logs in with their own Snowflake account) and **Key Pair** (the app authenticates as a shared service user with an RSA key pair — no browser login, tokens never expire mid-session).\n\n## OAuth\n\n### Step 1: Create an OAuth Integration in Snowflake\n\nTo enable OAuth for your Snowflake account, an administrator must first register the connected app.\n\n```python exec\nimport reflex as rx\nfrom flexgen.ui.components.markdown import get_base_component_map\n\ntry:\n    from flexgen.integrations.snowflake import SnowflakeAuthState\nexcept ImportError:\n    redirect_uri = (\n        \"https://build.reflex.dev/_reflex_oidc_snowflake/authorization-code/callback\"\n    )\nelse:\n    redirect_uri = SnowflakeAuthState.redirect_uri\n```\n\n```python eval\n# Actually render the real redirect_uri for copy/paste\nget_base_component_map()[\"pre\"](\n    f\"\"\"CREATE SECURITY INTEGRATION oauth_reflex_build_int\n  TYPE = OAUTH\n  ENABLED = TRUE\n  OAUTH_CLIENT = CUSTOM\n  OAUTH_CLIENT_TYPE = 'PUBLIC'\n  OAUTH_REDIRECT_URI = '{redirect_uri}'\n  OAUTH_ISSUE_REFRESH_TOKENS = TRUE\n  OAUTH_REFRESH_TOKEN_VALIDITY = 86400;\"\"\",\n    language=\"sql\",\n)\n```\n\n### Step 2: Log in via OAuth\n\nNOTE: you must use a non-admin account to complete the OAuth flow.\n\n## Key Pair\n\nKey-pair authentication connects as a Snowflake service user with a registered RSA public key. Use it when the app should have its own identity instead of a user's OAuth session.\n\n### Step 1: Generate an RSA key pair\n\nGenerate an unencrypted PKCS#8 private key:\n\n```bash\nopenssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt\n```\n\nOr generate an encrypted one, if your organization requires passphrase-protected keys at rest:\n\n```bash\nopenssl genrsa 2048 | openssl pkcs8 -topk8 -v2 aes256 -inform PEM -out rsa_key.p8\n```\n\nThen derive the public key:\n\n```bash\nopenssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub\n```\n\n### Step 2: Register the public key on a Snowflake user\n\nRun as an administrator, pasting the contents of `rsa_key.pub` without the `BEGIN/END PUBLIC KEY` lines:\n\n```sql\nCREATE USER IF NOT EXISTS svc_reflex TYPE = SERVICE DEFAULT_ROLE = <role>;\nGRANT ROLE <role> TO USER svc_reflex;\n\nALTER USER svc_reflex SET RSA_PUBLIC_KEY='MIIBIjANBgkq...';\n```\n\nTo print the `ALTER USER` statement with the key already formatted on a single line:\n\n```bash\necho \"ALTER USER svc_reflex SET RSA_PUBLIC_KEY='$(grep -v '^-----' rsa_key.pub | tr -d '\\n')';\"\n```\n\nThe `GRANT ROLE` is required — `DEFAULT_ROLE` only sets a preference and does not grant the role. The role needs `USAGE` on the warehouse, database, and schema the app will query. To verify the registration, compare `RSA_PUBLIC_KEY_FP` from `DESC USER svc_reflex` (Snowflake prefixes it with `SHA256:`) against the output of:\n\n```bash\nopenssl rsa -pubin -in rsa_key.pub -outform DER | openssl dgst -sha256 -binary | openssl enc -base64\n```\n\n### Step 3: Fill in the Key Pair tab\n\n- `SNOWFLAKE_USER`: the user the public key is registered on (e.g. `svc_reflex`)\n- `SNOWFLAKE_PRIVATE_KEY`: paste the full contents of `rsa_key.p8` (mangled newlines from copy/paste are fine)\n- `SNOWFLAKE_PRIVATE_KEY_PASSPHRASE`: only if the private key is encrypted. It is stored with the integration secrets and used to decrypt the key at connect time. To strip a passphrase from an existing key instead: `openssl pkcs8 -topk8 -in rsa_key.p8 -nocrypt -out rsa_key_plain.p8`\n\nThe warehouse and database dropdowns populate once the key pair authenticates, which doubles as a connection check.\n\nIf a private key is ever lost or leaked, generate a new pair and re-run the `ALTER USER ... SET RSA_PUBLIC_KEY` — Snowflake also supports `RSA_PUBLIC_KEY_2` for zero-downtime rotation.\n\n# Roadmap \n\nIn the future, this integration will be extended to support external OAuth\nflows, service principal authentication, and external network access.\n","packages/integrations-docs/src/integrations_docs/docs/stripe.md":"---\ndescription: Connect your apps to Stripe to accept payments, manage subscriptions, and handle billing securely.\n---\n# Stripe Integration\n\nThe **Stripe Integration** allows your app to use [Stripe](https://stripe.com/) to power secure payments, subscriptions, and billing workflows. Once connected, you can process transactions, manage customers, and trigger payment flows directly from your app.\n\n## What You Can Do\n\nWith Stripe, your app can:\n- **Accept one-time payments** or set up **recurring subscriptions**.  \n- **Manage customers**, payment methods, and invoices.  \n- Handle **refunds, payment confirmations**, and notifications.  \n- Automate billing flows and webhook-based actions.  \n- Build secure, PCI-compliant checkout experiences with ease.\n\n## Step 1: Obtain a Stripe API Key\n\n1. Go to your [Stripe Dashboard](https://dashboard.stripe.com/).  \n2. Navigate to **Developers → API Keys**.  \n3. Copy your **Secret Key** (or create a restricted key for added security).\n\n   * **Example:** `sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n> 💡 Use test keys in development environments and live keys in production.\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Stripe** in your app settings.  \n2. Paste your **Stripe API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can process payments and manage billing directly from workflows and UI actions.\n\n## Step 3: Notes\n\n* **Keep your API key secure:** Never expose your Stripe key in client-side code.  \n* **Use environment-specific keys:** Test keys for staging, live keys for production.  \n* **Secure transactions:** All payment processing is handled through Stripe’s PCI-compliant infrastructure.  \n","packages/integrations-docs/src/integrations_docs/docs/supabase.md":"---\ntags: Data Infrastructure\ndescription: Connect your apps to Supabase to use a hosted Postgres database with real-time capabilities and powerful APIs.\n---\n# Supabase Integration\n\nThe **Supabase Integration** allows your app to connect to [Supabase](https://supabase.com/) — a hosted Postgres database with real-time subscriptions, authentication, and file storage. Once connected, your app can query and update data securely, power dashboards, and sync workflows in real time.\n\n## What You Can Do\n\nWith Supabase, your app can:\n- **Read and write data** using Postgres through a simple REST or client API.  \n- Enable **real-time updates** that sync automatically to your UI.  \n- Use **row-level security** and access control for safe data management.  \n- Store and retrieve files with Supabase Storage.  \n- Integrate seamlessly with AI, dashboards, or internal tools.\n\n## Step 1: Obtain Your Supabase URL and Key\n\n1. Go to your [Supabase Project](https://supabase.com/).\n2. Choose the project you want to connect.\n3. Navigate to **Project Settings**.\n4. Go to **Data API** and copy your `Supabase_URL`.\n5. Then go to **API Keys** and copy your `Supabase_Key` (the secret key).\n\n   * **Example URL:** `https://your-project.supabase.co`  \n   * **Example Key:** `sb_xxxxxxxxxxxxxxxxxxxxxxxxxxxx.`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Supabase** in your app settings.  \n2. Paste your **Supabase URL** and **Supabase Key** into the fields.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can query and update your Supabase database directly from workflows and UI actions.\n\n## Step 3: Notes\n\n* **Keep your keys secure:** Never expose the `Supabase_Key` key in client-side code.  \n* **Use environment-specific keys:** Separate dev, staging, and production projects for clean access control.  \n* **Realtime support:** Supabase enables live syncing of data changes.  \n* **Row-level security:** Make sure to configure policies appropriately for your use case.\n","packages/integrations-docs/src/integrations_docs/docs/twilio.md":"---\ntags: Communication\ndescription: Connect your apps to Twilio to send SMS, WhatsApp messages, and voice calls programmatically.\n---\n# Twilio Integration\n\nThe **Twilio Integration** allows your app to use [Twilio](https://www.twilio.com/) to send and receive SMS, WhatsApp messages, and voice calls. Once connected, your app can trigger messages or calls directly from workflows, user actions, or automated events.\n\n## What You Can Do\n\nWith Twilio, your app can:\n- **Send SMS** messages to users or customers globally.  \n- **Send and receive WhatsApp messages**.  \n- **Make and manage voice calls** programmatically.  \n- Automate **notifications**, **alerts**, and **transactional messages**.  \n- Integrate messaging into AI workflows for dynamic, real-time communication.\n\n## Step 1: Obtain Twilio Credentials\n\n1. Go to your [Twilio Console](https://www.twilio.com/console).  \n2. Copy your **Account SID** and **Auth Token** from the dashboard.  \n\n   * **Example Account SID:** `ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`  \n   * **Example Auth Token:** `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Twilio** in your app settings.  \n2. Paste your **Account SID** and **Auth Token** in the input fields.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can send messages or make calls through Twilio directly in workflows and components.\n\n## Step 3: Notes\n\n* **Keep your credentials secure:** Never expose your Auth Token in client-side code.  \n* **Use environment-specific credentials:** Separate dev, staging, and production credentials.  \n* **Phone number setup:** Ensure you’ve configured a valid Twilio number for sending messages or calls.  \n* **Regulatory compliance:** Review Twilio’s messaging and voice compliance requirements for your region.\n","packages/reflex-base/README.md":"# reflex-base\n\nCore types for the Reflex framework.\n","packages/reflex-bench/README.md":"# reflex-bench\n\nMacro benchmarks for Reflex. `reflex-bench` drives benchmarks through one command\nline interface, stores every raw sample with the machine it ran on, and compares\nresults with statistics that say \"inconclusive\" instead of guessing.\n\nThe CLI is the only code path: CI runs the same commands and only adds output\ntargets. The harness never imports the reflex under test; benchmarks reach it\nthrough subprocesses, HTTP, sockets and a browser. This package is used inside\nthis repository only and is never published.\n\n```console\n$ uv run reflex-bench list --suite selftest\n$ uv run reflex-bench run --suite selftest\n$ uv run reflex-bench run selftest.noise --param shift=1.2 --baseline 0001\n$ uv run reflex-bench run --reflex 0.8.23 --suite selftest\n$ uv run reflex-bench ab --base git:main --head workspace --suite selftest\n$ uv run reflex-bench compare base.json head.json --format md\n$ uv run reflex-bench doctor\n$ uv run reflex-bench export result.json --to bmf\n$ uv run reflex-bench budgets check result.json\n$ uv run reflex-bench noise ../bench-data/runs/<profile_id> --format md\n$ uv run reflex-bench subjects list\n```\n\n## Commands\n\n| Command | What it does |\n| --- | --- |\n| `list [FILTER...] [--suite NAME]` | Benchmarks with their parameters, kind, metrics, suites and estimated duration. |\n| `run [FILTER...] [--reflex SPEC]` | Runs benchmarks against one reflex, prints the result table, autosaves the result and optionally compares it with a baseline. |\n| `ab --base SPEC --head SPEC [FILTER...]` | Measures two reflexes in alternation on this machine and compares them ([A/B runs](#ab-runs)). |\n| `show FILE [--samples]` | One result in detail, optionally with every raw sample. |\n| `compare BASE HEAD [--format term\\|md\\|json]` | Compares two results; `json` prints the annotated head result. |\n| `doctor` | Machine checks that affect measurement noise, with fix hints. |\n| `export FILE --to md\\|bmf [-o OUT]` | Pull request markdown or [Bencher Metric Format](https://bencher.dev/docs/reference/bencher-metric-format/). |\n| `budgets check FILE [--budgets BUDGETS]` | Checks a result against the metric maxima of `budgets.json` ([Size budgets](#size-budgets)). |\n| `noise PATH... [--kind daily] [--min-runs 10] [--format term\\|md\\|json]` | The per-metric noise table of stored results ([Noise table](#noise-table)). |\n| `subjects list` | The cached [subject](#subjects) venvs: spec, Python, key, size and last use. |\n| `subjects prune [--older-than 30d]` | Deletes venvs not used for that long (`30d`, `12h`, `90m`), leftovers of interrupted builds and git worktrees no venv uses. |\n\n`FILTER` is a glob on the benchmark id (`lifecycle.*`, `*.warm`). Suites are named\nselections: `smoke`, `pr`, `daily`, `macro` (the timings the CodSpeed macro\nrunner measures, see [CI](#ci)), `selftest` and `all` (every benchmark except\nthe self-tests). Self-tests only run when asked for, with `--suite selftest` or a\nfilter starting with `selftest`.\n\nMain `run` options (every effective value is printed in the header and stored in\nthe result's `policy` block):\n\n| Option | Default | |\n| --- | --- | --- |\n| `--reflex SPEC` | `workspace` | The reflex to measure (see [Subjects](#subjects)). |\n| `--python VERSION` | the harness's | The Python of subject venvs (major.minor of the interpreter running reflex-bench, which the workspace runs on). |\n| `--runs N` | automatic | Fixed number of timed runs. |\n| `--min-runs`, `--max-runs`, `--min-time` | 10, max(30, min-runs), 30 s | The automatic run count (below). |\n| `--warmup N` | per benchmark | Untimed runs, stored but excluded from statistics. |\n| `--timeout SECONDS` | per benchmark | Deadline of each `prepare`, `sample` and `conclude` call. |\n| `--param KEY=VALUE` | | Restricts a parameter to one value, or sets a new value or a hidden parameter. |\n| `--baseline NAME\\|FILE\\|NUMBER` | | Compares with a file, a named baseline or an autosave number (`0041`). |\n| `--save/--no-save`, `--save-as NAME`, `--json FILE` | autosave | Where to store the result. |\n| `--threshold PCT`, `--alpha FLOAT` | 3, 0.01 | Practical threshold and significance level of verdicts. |\n| `--fail-on regression\\|never`, `--fail-on-inconclusive` | never locally, regression when `CI=true` | Exit codes 2 and 3. |\n| `--smoke` | | One run, no warmup, no statistics: checks that each benchmark works. |\n| `--ndjson` | | Progress events as JSON lines on stdout; human output moves to stderr. |\n| `--seed INT` | random | Seeds each benchmark's RNG and the bootstrap; always recorded. |\n| `--keep` | | Keeps each benchmark's work directory. |\n| `--kind` | `local` or `ci` | The run kind recorded in the result (`pr`, `daily`, `backfill`, `aa`). |\n\nExit codes: `0` ok, `1` harness error (including usage errors and every benchmark\nfailing), `2` regression with `--fail-on regression`, `3` inconclusive result\nwith `--fail-on-inconclusive`, `4` nothing to compare (no metric has samples on\nboth sides with matching series keys, and no benchmark started failing). A\nbenchmark that fails or times out is reported with its status and does not stop\nthe run; when comparing, one that fails or times out in head but not in base (or\nis new) is a regression.\nCtrl-C during `run` exits with `130` after saving the benchmarks that finished,\nmarked with `\"interrupted\": true`; the benchmark in progress is left out, and `--save-as` keeps the old baseline.\n\nWith `CI=true` the output is plain (no colors, no live progress, one line per\nfinished benchmark) and `--fail-on` defaults to `regression`. Nothing else changes.\n\n## Subjects\n\nThe reflex under test, `--reflex SPEC` (`--base` and `--head` for `ab`):\n\n| SPEC | Meaning |\n| --- | --- |\n| `workspace` (default) | This checkout, in the harness's own environment. |\n| `0.8.23`, any PEP 440 version | `reflex==<version>` from PyPI. |\n| `git:<ref>` | A commit, branch or tag of the current repository, e.g. `git:main`, `git:v0.9.11`. |\n| `path:<dir>` | Another local checkout, e.g. `path:../reflex-wt-other`. |\n\nEvery spec but `workspace` runs in its own virtualenv, `<home>/venvs/<key>/`,\ncreated with `uv venv --relocatable --python <--python>` and never containing\nthe harness. The key is the first 16 hex digits of the SHA-256 of the subject's\nidentity (the version; the commit of a git ref; the absolute path, commit and\ndirty flag of a path), the `--python` value and the harness's extra subject\nrequirements (`SUBJECT_REQUIREMENTS`: `sqlmodel` and `alembic`, the ranges of reflex's `db` extra, for the playground's database, and `plotly`, which `rx.plotly` imports). A venv is built in a temporary directory and renamed\ninto place when complete, under a lock, so a half-built venv is never reused and\nconcurrent runs build it once. A `path:` subject with uncommitted changes (or\noutside git) is rebuilt every time. The build happens before anything is timed\nand says what it does (`building venv for reflex 0.8.23 (py3.12)…`, `reusing\nvenv …`).\n\nA `git:` subject is checked out as a detached git worktree in\n`<home>/src/<commit>/` (reused when present; a worktree keeps the tags the\npackages' versions are computed from). A checkout with a `uv.lock` is installed\nwith the dependency set of `uv export --frozen --no-dev --package reflex`,\nwhich lists `reflex` and every workspace package it needs (`reflex-base`,\n`reflex-components-*`, ...) as editable paths in the checkout, so the\ndevelopment versions reflex pins never come from PyPI; the other dependencies\nare the locked ones, and the exported list is kept in the venv as\n`reflex-bench-requirements.txt`. A checkout without a lock (older than uv) is\ninstalled directly, editable.\n\nThe subject records its interpreter, `reflex_version`, `python_version` and\n`extra.granian`, all read by running the subject's interpreter on package\nmetadata (the harness never imports reflex), plus `commit` and `dirty` for git\nand path subjects. Benchmarks get the subject's interpreter directory first on\n`PATH` in `ctx.env`, so commands reflex starts by name (reflex 0.8 starts\n`granian` in production mode) come from the subject's venv.\n`subjects list` and `subjects prune` manage the cached venvs.\n\n## Writing a benchmark\n\nBenchmarks live in modules of `reflex_bench.suites`; every module there is\nimported on discovery.\n\n```python\nimport time\n\nfrom reflex_bench.registry import Metric, benchmark\n\n\n@benchmark(\n    id=\"selftest.sleep\",\n    suites=(\"selftest\",),\n    kind=\"time\",  # time | startup | rate | latency | peakmem | track\n    params={\"ms\": [10, 50]},  # cartesian product: selftest.sleep[ms=10], [ms=50]\n    metrics={\"wall\": Metric(unit=\"s\", direction=\"lower\")},\n    warmup=1,\n    timeout=60,  # seconds per prepare/sample/conclude call\n    estimate=5,  # rough seconds per sample, for `list`\n    min_version=None,  # e.g. \"0.9.8\": older subjects report \"unsupported\"\n)\nclass Sleep:\n    \"\"\"Sleep for a fixed time; checks the timing pipeline.\"\"\"\n\n    def setup_cache(self, ctx): ...  # once per subject and parameter set\n    def setup(self, ctx): ...  # once per instance\n    def prepare(self, ctx): ...  # before each sample, untimed\n    def sample(self, ctx):  # one sample\n        time.sleep(ctx.params[\"ms\"] / 1000)\n\n    def conclude(self, ctx): ...  # after each sample, untimed\n    def cleanup(self, ctx): ...  # once at the end\n```\n\nEvery hook except `sample` is optional; `conclude` and `cleanup` always run, also\nafter a failure or a timeout. Further `@benchmark` arguments:\n`hidden_params={\"name\": default}` for parameters that are passed to hooks but are\nnot part of the name or the series key, `suite_params={\"smoke\": {\"sessions\":\n[10]}}` for the values a parameter takes when that suite is selected (a quick\nsubset of the grid; `--param` still wins), and `setup_timeout` (600 s) for\n`setup_cache`, `setup` and `cleanup`.\n\n**Metrics** are declared with `Metric(unit, direction, assume=\"nothing\",\ndescription=\"\")`. Values are stored in SI base units (`s`, `B`, `ev/s`, `1` for\ncounts); scaling to ms or MB only happens on display. `assume=\"exact\"` marks a\ndeterministic value: one run is enough and any variance is reported.\n\n**`sample(ctx)`** returns `None`, a dict of metric values, or\n`SampleResult(values, extra)` whose JSON-serializable `extra` is stored with the\nsample. The harness always times the call; a declared `wall` metric that\n`sample()` does not return is filled with that duration. Returning an undeclared\nmetric, or leaving out a declared one, fails the benchmark.\n\n**`ctx`** is a `reflex_bench.context.Context`: `subject` (the reflex under test:\n`python`, `reflex_version`, `commit`, `dirty`, ...), `params` (hidden ones\nincluded), `workdir` (fresh per instance, removed after `cleanup` unless\n`--keep`), `cache_dir` (persistent per subject commit, benchmark id and\nparameter set, for `setup_cache` results; the hook decides what to reuse),\n`env` (the environment for subprocesses: telemetry and update checks off,\n`NO_COLOR`, `PYTHONUNBUFFERED`, `PYTHONHASHSEED=0`, granian, the subject's\ninterpreter directory first on `PATH`), `rng` (seeded), `log`, `arm` and\n`dims`: `setup` may name how the values are measured there, e.g.\n`ctx.dims[\"memory_method\"] = \"cgroup\"`, and the scheduler copies it into the\nentry's `dims`, which are part of the series key, so differently measured\nvalues never pair up in a comparison.\n\nAll hooks of an instance run on one worker thread, so thread-bound resources\n(such as a sync Playwright browser) work across hooks. A hook that misses its\ndeadline ends the instance with status `timeout`; the stuck thread is abandoned\nand the remaining teardown hooks run on a fresh one (as they do after Ctrl-C),\nso `conclude` should kill whatever `sample` started. A hook still running a few\nseconds after teardown keeps the work directory and skips the benchmark's\nremaining parameter sets. `reflex_bench.registry.Instance` exposes the hooks as\nzero-argument methods and `reflex_bench.scheduler.make_context` builds the same\ncontext as the scheduler, for callers other than the scheduler.\n\n**Keep heavy processes per sample.** During [`ab`](#ab-runs) both arms'\nsessions are open at the same time, `setup` to `cleanup`. A benchmark that\nkeeps a heavy process (a server) alive between samples runs two of them at\nonce, which distorts both arms. Start per-sample processes in `prepare` or\n`sample` and stop them in `conclude`. This is not enforced. Two kinds of\nbenchmarks keep one server per instance on purpose, and say why in their\ndocstrings: `browser.prod.pageload` (a prod start includes a full frontend\nbuild, and an idle second server does not touch page load) and the `hmr.*`\nbenchmarks (a dev start plus hydration before every edit would multiply their\nrun time by about ten, and the other arm's server only idles while this one\nrecompiles).\n\n## Driving reflex\n\nBenchmarks start the reflex under test as a user does, `<python> -m reflex ...`\nwith the subject's interpreter, through `reflex_bench.drivers.app_process`:\n\n```python\nfrom reflex_bench.collectors.cgroup import CgroupScope\nfrom reflex_bench.drivers.app_process import AppProcess, cache_env, run_cli\n\nenv = {**ctx.env, **cache_env(reflex_dir=ctx.cache_dir / \"reflex\")}\nscope = CgroupScope() if CgroupScope.available() is None else None\nresult = run_cli(\n    ctx.subject.python,\n    [\"compile\"],\n    cwd=app,\n    env=env,\n    timeout=600,\n    scope=scope,\n    phases=True,\n    sample_memory=scope is None,\n).check()  # wall_s, cpu_s, peak_mem_bytes, timing, attribution()\n\nself.app = AppProcess(\n    ctx.subject.python,\n    app,\n    mode=\"prod\",\n    reflex_version=ctx.subject.reflex_version,\n    env=env,\n)\nreadiness = self.app.start()  # process-ready: ready lines + every port accepts TCP\nself.app.wait_http_ready()  # GET / (or /ping without a frontend) answers 200\n# conclude(): self.app.stop() kills the whole process tree\n```\n\nThe driver picks free ports, expects the ready lines of the subject's version\nand mode (0.8.23 prod runs sirv and the backend on two ports, 0.9 prod one\nport) and never trusts a line without a TCP probe. It runs with the `env` it\nis given: pass `ctx.env`, or `reflex_bench.context.subject_env(python)` outside\na benchmark, so the subject's commands come first on `PATH`. Each command runs in its own session; `stop()` and the end of\n`run_cli` kill the whole tree, children that started their own session\nincluded. Peak memory and CPU come from a transient cgroup v2 scope when\n`systemd-run` works (user manager, or sudo on CI), else from PSS sampling\n(`memory_method: pss_sampling`, never compared with cgroup peaks);\n`reflex-bench doctor` shows which. With `phases=True`, `attribution()` splits\nthe command's wall and CPU time between three classes of processes sampled\nfrom its tree: `install` (`bun`/`npm`/`pnpm`/`yarn` `install`/`add` and what\nthey start), `frontend` (`node`, `vite`, `react-router`, `esbuild` and what\nthey start) and `python`, the interpreter and everything else. A tool's wall\nis the time it was alive; python's is the total minus the time any tool was\nalive, when the interpreter only waits. `cpu` per class is checked against\nthe measured total (`mismatch` beyond 10 %), `idle` is wall time not spent on\nCPU, and `python_breakdown` keeps the `[timing]` phases of the compile.\n`selftest.app.compile` and `selftest.app.dev_ready` exercise all of it against\na blank app.\n`run_cli(..., prefix=(\"-c\", \"import reflex\"))` runs other interpreter\narguments than `-m reflex` through the same process tree code.\n\n## Fixtures\n\nA fixture is the app a benchmark drives, described by a `FixtureDoc` (`name`,\n`content_hash`, `params`). A benchmark sets `ctx.fixture` in `setup_cache` or\n`setup`, and its entry records the name in `dims` (`{\"fixture\": \"playground\"}`,\npart of the pairing and series keys) and the hash in `fixture_hash` (part of\nthe series key only): an edited fixture pairs with its old self and `compare`\nreports the pair as not comparable, `fixture content hash differs`, unless\n`--force`. Hooks record anything else that separates series in `ctx.dims`.\nOne invocation drives several fixtures, so the document-level `fixture` stays\n`null`.\n\n- **The playground**, `examples/playground`: a committed app whose hash is the\n  line in its `.content-hash` (see its README for the element ids and hot reload\n  targets benchmarks rely on). `materialize_playground(dest)` copies it without\n  build output. It has 21 pages (about 3000 component instances, 16 states)\n  and a sqlite table: loading the app seeds 2000 fixed rows into an empty table,\n  in one transaction, so each staged copy creates its `playground.db` once. It\n  needs `sqlmodel`, `alembic` and `plotly`, which\n  `SUBJECT_REQUIREMENTS` installs into subject venvs; the workspace gets them\n  from the `dev` group.\n- **Generated apps**, `reflex_bench.fixtures.generate`: `GenParams(pages,\n  components_per_page, state_vars, substate_depth, computed_vars, seed)` gives a\n  deterministic app of any size, hashed from the generator's source and the\n  parameters. Its hot reload targets follow the playground's pragma form and\n  are listed in `bench-manifest.json`. `uv run python -m\n  reflex_bench.fixtures.generate --pages 10 DEST` writes one to look at.\n\n`ensure_fixture(ctx.cache_dir, describe, make)` keeps the app in\n`cache_dir/app` with a `fixture.json` stamp, and rebuilds it when the stamp no\nlonger matches: `setup_cache` directories are keyed by subject and parameters,\nnot by the app. `bump_marker(path, target, n)` sets a hot reload target's\nstring to `m-<n>-<target>`; the benchmark restores the module in `conclude`, so\nthe cached app stays the fixture its stamp describes.\n\nThe `lifecycle.*` benchmarks (`reflex_bench/suites/lifecycle.py`) time `init`,\n`compile`, `export`, `run` until HTTP-ready and `import reflex as rx; rx.App;\nrx.State` (the import alone is lazy), each in a cache state its id names\n(`cold`, `warm`, `incremental`); the module docstring lists which caches each\none starts from. No sample downloads anything: a subject downloads bun once,\ninto its shared `REFLEX_DIR` (`ctx.subject_cache_dir/reflex`), and installs the\nplayground's packages once, into its shared bun cache\n(`ctx.subject_cache_dir/bun-cache`); a cold state is a fresh directory that\nthese primed copies fill (`init.cold` gets a copy of bun, `compile.cold` a fresh\napp copy with the primed lockfile that links its packages from the cache), so a\nsample measures reflex and bun, not the network. Each `time` benchmark chooses its collector once, in\n`setup`, and records it in `dims` (`collector: cgroup | fallback`), so cgroup\npeaks and PSS peaks never share a series.\n\n## Fixture apps\n\nThe browser and hot reload benchmarks drive `examples/playground` (see its\nREADME for the element ids and `# bench:hmr-target` pragmas they rely on). The\nharness reads it from the checkout it runs in, never from the subject's\nenvironment, so `reflex-bench` must run from a reflex checkout.\n`reflex_bench.fixtures.prime(ctx)` copies it into the instance's cache directory\n(`<cache>/app/<arm>`: in an A/A run both arms share a cache directory, and two\nservers must not run in one app), without build output, and compiles it once\n(bun and the frontend packages), so the benchmarks' own starts are warm. The\nstaged copy is what the hot reload benchmarks edit; the checkout never changes.\nEvery sample records the playground's `.content-hash` in\n`extra[\"fixture_hash\"]`. `reflex_bench.fixtures.FIXTURES` maps the `app`\nparameter of the hot reload benchmarks to a staging function; `playground` is\nthe only one so far.\n\n## Event benchmarks\n\n`reflex_bench.suites.events` measures how many events the playground\n(`examples/playground`) answers and how fast. Each benchmark instance starts it\nonce as a production backend (`reflex run --env prod --backend-only`, one\ngranian worker), and each sample drives it for a few seconds with\n`reflex_bench.drivers.events`, a socket.io load generator that speaks reflex's\nevent websocket over `websockets` (no python-socketio). Sessions are browser\ntabs: each connects with its own token, hydrates like a page load, then sends\n`BenchState.set_seq*` events whose delta echoes a sequence number.\n\nThe grid holds the common points, about 30 minutes with the default policy.\nReflex's default state manager is disk, or redis with a `redis_url`, so every\nbenchmark runs on `disk` (and on `redis` when `REFLEX_REDIS_URL` is set), at 10\nsessions except `at_1hz` (200 sessions) and the fan-out (25 linked sessions).\nOnly `simple` also runs on `memory`, the framework's cost without state I/O,\nand at 50 sessions. Other sizes run by name with `--param`, e.g.\n`reflex-bench run 'events.complex.capacity' --param sessions=200`.\n\nCI minutes are scarce, so `smoke` runs two points, about 2 minutes per reflex\nwith the default policy: `events.simple.capacity[manager=disk,sessions=10]`\nand `events.simple.latency[manager=disk,sessions=10,rate=500]`. `daily` adds\nthe shared state at the same point,\n`events.shared_contention.capacity[manager=disk,sessions=10]` and\n`events.shared_contention.latency[manager=disk,sessions=10,rate=auto]`, and\n`events.shared_fanout.broadcast[manager=disk,linked=25]`. The other shapes,\nthe knee and `at_1hz` run with `--suite all` or by name.\n\n| Benchmark | Suites | Parameters | Load | Metrics |\n| --- | --- | --- | --- | --- |\n| `events.<shape>.capacity` | `smoke`, `daily` (simple, `manager=disk`, `sessions=10`) | `manager`, `sessions` 10 (simple: 10, 50) | closed loop, 3 s after 1 s | `throughput`, `service_p50`, `cpu_per_event` |\n| `events.<shape>.latency` | `smoke`, `daily` (simple, `manager=disk`, `sessions=10`, `rate=500`) | `manager`, `sessions`, `rate` | open loop, 5 s after 1 s | `response_p50`, `p90`, `p99`, `max`, `throughput`, `unanswered`, `cpu_per_event` |\n| `events.shared_contention.capacity` | `daily` (`manager=disk`, `sessions=10`) | `manager`, `sessions` 10 | the same as `capacity`, every session linked to one `rx.SharedState` board | the same as `capacity` |\n| `events.shared_contention.latency` | `daily` (`manager=disk`, `sessions=10`, `rate=auto`) | `manager`, `sessions`, `rate` | the same as `latency`, every session linked to one board | the same as `latency` |\n| `events.shared_fanout.broadcast` | `daily` (`manager=disk`, `linked=25`) | `manager`, `linked` 25 | one linked session sends, closed loop, 3 s after 1 s; answered once every linked session has the delta | `throughput`, `broadcast_p50`, `broadcast_p99`, `fanout_spread_p50`, `cpu_per_event` |\n| `events.simple.knee` | (`all`) | `manager`, `sessions` 10 | open loop at 10 % to 110 % of the capacity, 4 s after 1 s each | `knee_rate`, `low_load_p99` |\n| `events.sessions.at_1hz` | (`all`) | `manager`, `sessions` 200 | open loop, 1 ev/s per session, 10 s after 3 s | `response_p50`, `response_p99`, `unanswered`, `cpu_per_event` |\n| `selftest.events.calibrate` | `selftest` | | the generator against an echo server: closed loop, then open loop at 1500 ev/s | `closed_ceiling`, `open_lag_p99` |\n\n- **Shapes**: `simple` (`set_seq`), `complex` (three vars behind a chain of\n  three computed vars), `cross` (`get_state` of another state), `background` (a\n  background task). Background tasks may finish in any order, so for\n  `background` an answer that overtakes an earlier event counts as\n  `out_of_order` without making that event unanswered. `shared_contention`\n  (`BoardState.set_seq_shared`) links every session to one board, so each\n  event is fanned out to all the others.\n- **`manager`**: `memory` and `disk`, plus `redis` when `REFLEX_REDIS_URL` is set\n  in the harness's environment when the suite is imported. The URL reaches only\n  the redis instances: reflex uses redis whenever a URL is configured.\n- **`rate`**: `auto` offers half the capacity that a 2 s closed-loop probe\n  measures once per instance, so each arm of an `ab` run is loaded to the same\n  share of its own capacity; `--param rate=N` offers `N` events per second to\n  both, which compares the same absolute load. `smoke` and `daily` offer 500,\n  the same load from one day to the next.\n- **One backend per instance**: it starts in `setup`, which also warms it with\n  the probe, and stops in `cleanup`, so its samples share one warm server; in\n  an `ab` run both arms' backends are up, one idle while the other is measured.\n- **Open and closed loop**: the open loop sends on a fixed schedule whatever\n  the server does and times each answer from the *planned* send time, so a\n  stall counts in every event it delays (no coordinated omission); events\n  without an answer count as `unanswered`, never dropped. The closed loop sends\n  the next event when the previous one is answered: it measures capacity and\n  service time (answer minus actual send), never user latency.\n- **Rates count the window only**: `throughput` (`answered_rate`) is the\n  answers that arrived within the measured window divided by its length, the\n  same as `answered_per_second` summed. The drain after the window only decides\n  which events are `unanswered`; the answers it collects still count in the\n  response percentiles.\n- **Per run, not pooled**: every sample's percentiles come from that run's\n  events; `response_p99` of a run with fewer than 10 000 answered events is kept\n  with `p99_underpowered` in its extra data. Each sample's extra data also holds\n  a 120-bucket log histogram (10 μs to 100 s) for pooled percentiles on display.\n- **CPU per event** is the server tree's CPU time in the measured window divided\n  by the answered events: from its cgroup scope (`cpu_method: cgroup`) or,\n  without one, summed over its processes with psutil (`cpu_method: psutil`),\n  including the children they reaped, so a worker that exits in the window\n  still counts. A CPU time that goes back fails the sample.\n- **Pinning**: on Linux with four CPUs or more, the server runs on the lower\n  half of the physical cores (CPU 0 excluded) and the generator on the upper\n  half, so no core is shared between them through SMT (the kernel's\n  `thread_siblings_list`; without it every CPU counts as a core), with up to 4\n  generator processes (1 up to 10 sessions); `pinning` in the extra data\n  records the split.\n- **Self-check**: a load fails it when a generator process used more than\n  75 % of a core, when the p99 of the send lag (actual minus planned send\n  time) exceeds the larger of 1 ms and 10 % of the median response, or when\n  less than 98 % of the offered events went out in the window. The rules judge\n  the generator alone: a lag tail inflates the response tail by as much,\n  whatever caused it, so the sample fails with `generator saturated` at once\n  and is never taken again. `selftest.events.calibrate` fails the same way\n  when the generator cannot offer 1500 ev/s, three times the highest fixed rate\n  of the suite, against an echo server.\n\nNot parameters yet: injected redis latency, uvicorn instead of granian, and\nmore than one backend worker.\n\n## Memory benchmarks\n\n`reflex_bench.suites.memory` answers how much memory the playground takes,\nwhether it grows, and whether it fits a 512 MiB box. Samples are untimed:\nevery metric is bytes (lower is better) except `passed`. Each sample starts a\nfresh backend (`reflex run --env prod --backend-only`, one granian worker), as\nthe event benchmarks do; `memory.dev.idle` starts the dev server instead.\n\n| Benchmark | Suites | Parameters | One sample | Metrics |\n| --- | --- | --- | --- | --- |\n| `memory.compile.peak` | `daily` | `command` compile, export | `reflex compile` or `reflex export --env prod` of the compiled playground | `peak_mem` |\n| `memory.idle` | `smoke` (memory), `daily` | `manager` | 5 s after `/ping` answers, the median of three PSS reads a second apart | `pss`, `pss_anon`, `pss_file` |\n| `memory.idle.allocator` | (`all`) | `allocator` mimalloc, arena2 | the same with `PYTHONMALLOC=mimalloc` or `MALLOC_ARENA_MAX=2` | the same |\n| `memory.dev.idle` | `daily` | `manager` memory | the same for `reflex run --env dev`, backend and vite dev server, 10 s after the page answers HTTP (no browser, so vite has transformed only what that request needed); the USS of the node, bun and esbuild processes is split from the python ones in the extra data (`backend_uss_bytes`, `frontend_uss_bytes`) | the same |\n| `memory.per_session` | `daily` (`max_sessions=500`) | `manager`, `max_sessions` (1000) | hold 0, 50, 100, 250, 500 and 1000 idle sessions, fit PSS per session; disconnect; wait for the states to expire | `bytes_per_session`, `bytes_per_session_ci_hi`, `residual_after_disconnect`, `residual_after_expiry` |\n| `memory.leak` | `daily` (`events=50000`) | `manager`, `events` (100000) | a closed loop of 10 sessions while the tree's anonymous PSS is sampled | `passed`, `bytes_per_event_ci_hi` |\n| `memory.boot_512mb` | `daily` (memory) | `manager` | compile, then boot and serve, under `MemoryMax=512M` with swap off | `passed`, `peak_compile`, `peak_boot`, `peak_serve` |\n| `memory.boot.min_limit` | (`all`) | `manager` memory | bisects `MemoryMax` from 64 to 1024 MiB in 32 MiB steps over boot and serve | `min_limit` |\n\n- **Methods**: peaks come from a cgroup v2 scope's `memory.peak` where the host\n  can start one (user systemd, or `sudo systemd-run` on CI), else from PSS\n  sampled every 50 ms; steady-state values are the summed PSS of the server's\n  process tree on every host, with the scope's `memory.current`, `anon` and\n  `file` in the extra data when a scope holds the running server (the compile\n  peak reads its scope after the command exited, so it records only whether\n  the peak was reset). `memory_method` in the dims\n  (`cgroup` or `pss_sampling`) names the collector of the values, so cgroup and\n  PSS numbers never share a series. The limit benchmarks need a scope and fail\n  with `cgroup scopes are unavailable: <reason>` without one: nothing else can\n  enforce a limit. `reflex-bench doctor` shows what the host has.\n- **What PSS shows**: the memory the tree holds from the kernel, shared pages\n  split between the processes. CPython and glibc keep freed memory for reuse\n  and rarely hand it back, so a number that does not drop means the process did\n  not shrink, not that something leaks. File-backed pages are also split with\n  processes outside the tree that map the same files (the harness's own\n  interpreter), so `pss_file` moves by a few MB between otherwise identical\n  samples; `pss_anon` is the steadier trend.\n- **Per session**: the sessions connect and hydrate like page loads, then stay\n  idle, held by `reflex_bench.drivers.events.hold_sessions` in a separate\n  process. The server runs with `REFLEX_REDIS_TOKEN_EXPIRATION=<expiry_s>`\n  (hidden; 0, the default, sizes it from the sweep: its settling and reading\n  time, 2 s per hold and a 5 s margin, 23 s for 500 sessions), longer than the\n  sweep: no state manager frees a state when its session disconnects, reflex\n  0.9's memory and disk managers and 0.8's disk manager free it after the\n  expiration, and 0.8's memory manager never does. A sweep that outlasts the\n  expiration fails the sample; a slow host can raise `expiry_s`. The residuals\n  are PSS over the idle baseline. `baseline_bytes_per_session` in the extra\n  data is the same sweep against the in-harness echo server: the floor of a\n  Python `websockets` server, not of python-socketio (the harness does not\n  depend on python-socketio); it is measured once per instance, while the\n  first sample's states expire. The sweep's steps below `max_sessions` are 50,\n  100, 250 and 500, so the slope's t interval has at least three degrees of\n  freedom. The tree's PSS is flat within 0.2 MiB from the moment a hold is\n  ready (against steps of 8 to 47 MiB), so a step settles for 1 s and is read\n  three times 0.5 s apart: about 2.5 s each, and a sample about 40 s.\n- **Leak**: a 5 s closed-loop probe sizes the warmup (`warmup_events`, hidden,\n  5000) and the window (`events`, with 10 % of room); the tree is sampled every\n  hundredth of the window, between 0.1 s and 1 s apart. The x axis is the events\n  answered since the window started (`answered_per_second` of the load), the y\n  axis the anonymous PSS: file-backed pages do not leak. The sample fails with\n  `LeakDetected` when the upper end of the slope's 95 % interval exceeds\n  `tolerance_bytes_per_event` (hidden, 100 B, that is 100 MB per million\n  events) *and* each half of the window grows on its own (the lower end of its\n  slope's interval is above zero): heap warm-up flattens out and one allocator\n  step lifts one half only, a leak grows through both. One 1 MiB arena step in\n  50 000 events is about 30 B per event. An unanswered event or a failed\n  session fails the sample, since the event count would be wrong. `passed` is\n  the gate; the slope itself and the growth over the window are in the extra\n  data (`slope_bytes_per_event`, `growth_bytes`), since near zero they move by\n  hundreds of percent between identical runs. `timeline` in the extra data\n  holds up to 500 `[events, anonymous PSS, USS of the python processes]`\n  points.\n- **512 MiB**: the compile runs in one scope, the server boots and serves 5\n  closed-loop sessions for 5 s in another, each with `MemoryMax=<limit_mb>M`\n  (hidden, 512) and `MemorySwapMax=0`, and each scope is read before its tree\n  stops. A phase that fails, or any `oom` or `oom_kill` in `memory.events`,\n  fails the sample with `MemoryLimitExceeded` naming the phase, the counters,\n  the peak and the log tail. The peak is reset between boot and serve where\n  the kernel can (Linux 6.12 and later; `peak_reset` in the extra data says\n  so), else the serve peak includes the boot. The published 512 MiB number\n  comes from an\n  amd64 reference profile (Fly's `shared-cpu` machines are amd64); arm64 runs\n  are a trend.\n- **Allocators**: `--param allocator=mimalloc|arena2` also works on `memory.idle`,\n  `memory.per_session` and `memory.leak`, and puts the allocator in the dims.\n  mimalloc needs the subject's Python to be 3.13 or later.\n\nNot measured yet: a leak per session (connect/disconnect churn) or per page\nload, redis's `used_memory` per session, and peaks per phase within one command\n(they need `memory.peak` resets, Linux 6.12).\n\n**Finding a leak** (manual; tracemalloc slows the server and inflates its\nmemory, so it never runs in a measured sample). Add a temporary handler to the\napp's state:\n\n```python\n@rx.event\ndef heap_snapshot(self, seq: int):\n    import time, tracemalloc\n\n    tracemalloc.take_snapshot().dump(f\"/tmp/heap-{time.time_ns()}.bin\")\n    self.last_seq = seq\n```\n\nstart the backend with tracemalloc on in every process\n(`PYTHONTRACEMALLOC=25 GRANIAN_WORKERS=1 REFLEX_STATE_MANAGER_MODE=memory\nuv run reflex run --env prod --backend-only --backend-port 8000`), and drive\nit with the generator: a snapshot, a load, another snapshot.\n\n```python\nfrom reflex_bench.drivers.events import EventShape, LoadPlan, run_load, seq_payload\n\nstate = \"reflex___state____state.playground___state____bench_state\"\n\n\ndef load(handler: str, sessions: int, duration_s: float) -> None:\n    shape = EventShape(f\"{state}.{handler}\", seq_payload, state, \"last_seq_rx_state_\")\n    run_load(\n        LoadPlan(\n            backend_url=\"http://localhost:8000\",\n            reflex_version=None,\n            shape=shape,\n            sessions=sessions,\n            mode=\"closed\",\n            rate=None,\n            warmup_s=0,\n            duration_s=duration_s,\n        )\n    )\n\n\nif __name__ == \"__main__\":\n    load(\"heap_snapshot\", 1, 0.001)\n    load(\"set_seq\", 10, 60)\n    load(\"heap_snapshot\", 1, 0.001)\n```\n\nThen compare the two snapshots by line:\n`first, second = map(tracemalloc.Snapshot.load, sorted(glob.glob(\"/tmp/heap-*.bin\")))`\nand print `second.compare_to(first, \"lineno\")[:20]`.\n\n## Wire sizes\n\n`reflex_bench.suites.wire` counts the bytes that cross the event websocket: what\na slow link pays for, which no timing or CPU metric shows. One session connects\nto a fresh production backend per sample (`reflex run --env prod\n--backend-only`, one granian worker, the memory state manager) and sums the\npayload bytes of every frame it sends and receives (a text frame's UTF-8\nlength; the HTTP handshake is not a frame). Sizes are deterministic for a given\napp and reflex version, so every metric is exact and a sample is one run.\n\n| Benchmark | Suites | Parameters | One sample | Metrics |\n| --- | --- | --- | --- | --- |\n| `wire.hydrate` | `pr`, `smoke`, `daily` | | connect and hydrate the playground's index route, until the delta that sets `is_hydrated` | `hydrate_sent_bytes`, `hydrate_received_bytes`, `hydrate_frames` (received) |\n| `wire.event` | `pr`, `smoke` (simple), `daily` | `shape` simple, complex, cross, background | after hydration, one `BenchState.set_seq*` event: the request frame, and every frame received until the delta echoing its sequence number | `request_bytes`, `response_bytes`, `response_frames` |\n| `wire.navigate` | `pr`, `smoke` (item), `daily` | `route` counter (`/counter`), item (`/item/42`, the dynamic `/item/[item_id]` page) | after hydration of `/`, a client-side navigation: the `on_load_internal` frame the frontend's router effect sends from the new route, and every frame received until the delta that sets `is_hydrated` again | `request_bytes`, `response_bytes`, `response_frames` |\n| `wire.delta` | `daily` | `change` set_scalar, append_item, set_one_item, set_dict_key, update_row_field | the same for one small change to a large collection of the generated `wire_delta` app | `response_bytes` |\n\n- **Replies span frames**: `response_bytes` sums every frame from the request\n  until the echo, so 0.8.23's empty update before a background task's delta\n  counts, as does any delta of another state. The extra data keeps the echo\n  frame (`reply`), the largest frame, and `delta_bytes`, the bytes of each\n  substate's part of the deltas re-serialized compactly.\n- **Keepalives do not count**: an engine.io ping and its pong are timing, not\n  payload, so a slow run moves the same bytes as a fast one.\n- **`wire.navigate`** sends what the frontend sends on a route change: one\n  `on_load_internal` with the new route's `router_data`. `update_vars_internal`\n  goes first only once the browser holds a value of a client storage var (the\n  playground's `/storage` page sets some); a fresh browser holds none, on 0.8.23\n  and 0.9 alike, so neither the hydration nor the navigation sends it. The reply carries the root state's `router` and,\n  on the dynamic route, the route argument.\n- **`wire.delta`** does not use the playground: its `setup_cache` writes a\n  small app whose state holds 1000 ints in a list, 1000 keys in a dict and 200\n  dict rows, and compiles it. Every handler also sets `last_seq` (the echo), so\n  the deltas differ only by the collection they carry; `set_scalar` is the\n  control. A whole collection resent for a one-item change shows as\n  `response_bytes` far above the control's.\n- **Dims**: `fixture` names the app (`playground` or `wire_delta`); for\n  `wire.delta`, the entry's `fixture_hash` is the generated source's content\n  hash, so `compare` rejects a pair across a change to the generator.\n\n`AppProcess.t0` is the `time.perf_counter()` taken just before the spawn, the\norigin of every readiness time, and `AppProcess.log_lines()` returns the output\nwith the time each line was read (seconds since `t0`), so other clocks and log\nlines can be put on one timeline.\n\n## Driving a browser\n\n`reflex_bench.drivers.browser` drives headless Chromium through Playwright's\nsync API. Install the browser once:\n\n```console\n$ uv run playwright install --only-shell chromium\n```\n\nHeadless runs launch the headless shell, so the full Chromium is not needed\n(`--only-shell` exists from Playwright 1.49). On a bare CI runner add\n`--with-deps` for the system libraries, and cache `~/.cache/ms-playwright`\nkeyed on the runner's architecture. `reflex-bench doctor` reports whether a\nchromium is installed.\n\n```python\nfrom reflex_bench.drivers.browser import Browser\n\nself.browser = Browser(cpu_throttle=1)  # setup(): one browser per instance\nself.browser.start()  # the calling thread owns it\nresult = self.browser.interactive(self.app, \"/\")  # tier 3, also set in app.readiness\ntab = result.tab  # a page in a fresh context (cold cache); tab.page is Playwright's\ntab.watch(\"edit\", \"text\", \"#bench-marker-leaf\", marker)\nmark = tab.wait_mark(\"edit\", timeout=90)  # {\"perf\": ..., \"epoch\": ...}\n# conclude(): self.browser.close_tab(tab); cleanup(): self.browser.close()\n```\n\nEvery page gets `drivers/bench_page.js` as an init script, which runs before\nany page script in every document, reloaded ones included. The page emits the\n\"done\" signal itself: `tab.watch(id, kind, selector, expected)` has it record a\n*mark* the first time a condition holds (`present`, `text`, `changed`,\n`style:<property>` or `naturalWidth`), checked on every DOM mutation and every\nanimation frame (a computed style or a loaded image is no mutation); a watch,\nand its mark once recorded, survives a reload. `#bench-hydrated` is always watched: `interactive()` waits\nfor it (tier 3: the websocket connected and the first state update applied).\nThe script also collects paint, largest contentful paint, long task and long\nanimation frame entries (`tab.timings()`). `tab.set_alive()` tags the document\nand `tab.alive()` reads the tag back: a full reload loses it. Uncaught page\nerrors fail a sample (`tab.raise_errors()`), console errors and warnings are\ncounted (`tab.drain_console()`, the last error's text in `tab.last_error`), and\nwebsocket payload bytes and HTTP wire bytes (headers included, from the\nDevTools `Network.loadingFinished` events) are summed per page.\n\n**Clocks.** A mark carries `performance.now()` (since navigation start) and\n`Date.now()`. `browser.anchor`, the tightest of three back-to-back reads of\n`time.perf_counter()` and `time.time()` taken at start, maps page time onto\n`perf_counter()`: `anchor.perf_at(epoch) - app.t0` puts a page event on the\napp's timeline within 1 ms (`Date.now()`'s resolution) plus the anchor's\nspread, the harness's own share (well under a microsecond), which is stored\nwith the samples.\n\n**Threads.** The sync API refuses calls from any thread but the one that\nstarted it (`greenlet.error: Cannot switch to a different thread`), and\nteardown hooks run on a fresh thread after a timeout or Ctrl-C. `close()`\ncloses normally on the owner thread and kills from any other; `kill()` never\ntouches Playwright: it SIGKILLs the Playwright driver (the harness's child) and\nthe process group Chromium's root (the driver's child) leads with all its\nhelpers, both found at `start()`, so a hook still blocked in the page gets an\nerror at once. `close_tab()` from another thread kills the\nbrowser too: after a timeout the instance is over. Browsers still open when the\nharness exits are killed. A `Browser` belongs to one instance and arm; during\n`ab` two of them coexist. Playwright is imported on `start()`, which keeps\n`reflex-bench list` about 0.1 s faster.\n\n## Browser benchmarks\n\n| Id | Suites | What one sample measures |\n| --- | --- | --- |\n| `browser.dev.ready` | pr, daily, macro | `reflex run` start to `process_ready` (tier 1), `http_ready` (tier 2) and `interactive_ready` (tier 3), seconds since the spawn; also `nav_to_interactive` (in the page) and `fcp` |\n| `browser.preview.ready` | daily (reflex 0.9.8+) | the same with `--env preview` |\n| `browser.prod.ready` | daily | the same with `--env prod`, frontend build included |\n| `browser.prod.pageload[cpu=1\\|4]` | daily | loading `/` of one prod server in a fresh context (cold cache), CPU throttled 4 times with `cpu=4`, read as soon as the page is interactive: `fcp`, `lcp` (the same paint on the playground), `interactive`, `tbt` (long tasks' time beyond 50 ms before interactive), `ws_bytes`, `transfer_bytes` (wire bytes, headers included; both exact: the same page transfers the same bytes) |\n\nThe `ready` samples store the gaps between the tiers in `extra[\"gaps\"]`. Page\nload metrics are noisy: read the median and its confidence interval over at\nleast 6 runs (outliers are counted, not dropped).\n\n## Hot reload benchmarks\n\nEach `hmr.*` instance starts one app (`reflex run --loglevel debug`) and one\npage, then per sample rewrites the staged app and waits until the page shows\nthe change. The edit's content is built in `prepare`; `sample` writes it to a\nsibling temporary file and moves it over the target, taking `t0` just before\nthat one `os.replace`, and returns as soon as the page's mark is there.\n`latency` is the page's mark minus `t0`, on the wall clock of both. Every edit\nwrites a unique value, so a stale page never satisfies a watch. `conclude`\nwaits until the page has been quiet for 0.5 s (no pending watch, no DOM\nchange), restores the file and waits until the page shows the original and is\nquiet again, which is also the wait between edits. Every hook's waits share\none 90 s deadline. `warmup` is 3 edits.\n\n| Id | Edit | Done when the page shows |\n| --- | --- | --- |\n| `hmr.render.leaf` | the `leaf` pragma literal (index page only) | the new text in `#bench-marker-leaf` |\n| `hmr.render.root` | the `root` pragma literal (every page) | the new text in `#bench-marker-root` |\n| `hmr.handler` | the `handler` pragma literal, set by an event handler | the new value in `#bench-handler-value`; the harness clicks `#bench-handler` every 250 ms (`extra[\"clicks\"]`) |\n| `hmr.css` | the `.bench-hooks` font size in `assets/playground.css` | the computed font size |\n| `hmr.asset` | `assets/mark.svg` gets a `width` and `height` | `#bench-mark`'s `naturalWidth` (HTTP cache off); the harness refreshes the page every 250 ms (`extra[\"reloads\"]`) |\n| `hmr.reconnect` | none: SIGKILL of granian's worker, then SIGHUP to its supervisor, since granian's dev reloader never respawns a worker that died on its own | `#count` changes on `/counter`; the harness clicks `#increment` every 250 ms |\n| `hmr.watcher` | the `leaf` literal | `latency` is granian's `Changes detected` line (its `reload_tick` is 100 ms) |\n\nEvery benchmark but `hmr.watcher` has a `.preview` twin for `--env preview`\n(reflex 0.9.8+). Preview serves a static build that a hot reload rebuilds and\nthat shows after a refresh, so preview twins whose change needs a new page\nreload it (waiting for its load event) every 250 ms until it shows\n(`extra[\"reloads\"]`).\n\n`full_reloads` records whether the sample's page reloaded to show the change\n(the mark carries the document's `tab.alive()` tag; a reloaded document lost\nit). For the render, handler and reconnect benchmarks a reload is no hot\nupdate: `conclude` fails the sample with `FullReloadError`, also when the page\nreloads right after showing the hot update, so `latency` only holds hot\nupdates. For `hmr.css` a reload may be how the change shows: `latency` is the\ntime until it shows. A change the page never shows by itself (no hot update,\nno reload, within the deadline) fails the sample: the harness does not refresh\na dev page for it. The error then says when granian saw the change, when the\nreload's last `[timing]` line came and whether the page reloaded, so it tells\nwhich side dropped the change. A stylesheet hot update that vite logged\n(`[vite] ... hmr update`) 5 s ago without the page applying it fails the sample\nat once (`DroppedUpdateError`, naming the value the page still shows) instead\nof waiting the deadline out. `hmr.asset` refreshes the page itself in every\nmode: vite has no module for a file of `public/`, so a change to one reaches\nno page and a user refreshes for it; `latency` is the time until a refresh\nshows the new file and `extra[\"reloads\"]` counts the refreshes.\n`extra[\"hops\"]` places each sample's backend steps, in seconds\nsince the edit: `watcher_seen_s` (granian's line), `compile_done_s` (the\nreload's last `[timing]` line) and `dom_updated_s` (the page's mark).\n\n## Size budgets\n\n`size.export[app=playground]` (suites `pr` and `daily`) measures what a\nproduction build of `examples/playground` ships. Its `setup` copies the files\ngit tracks of the example into the instance's work directory (each arm of an\n`ab` run gets its own copy; `--keep` keeps it) and runs `reflex export\n--frontend-only --no-zip --env prod` there; bun stays cached in reflex's data\ndirectory under the cache directory. `sample` then measures the files on disk.\nOne export gives every metric, and every metric is exact, so one sample is\ntaken:\n\n| Metric | What |\n| --- | --- |\n| `initial_raw`, `initial_gzip`, `initial_brotli` | The JS and CSS the first page loads: the files the prerendered `index.html` references with `<link rel=\"modulepreload\">`, `<link rel=\"stylesheet\">` or `<script src>`. URLs of other hosts are not part of the build. |\n| `total_raw`, `total_gzip`, `total_brotli` | Every file of `.web/build/client` except compression sidecars. |\n| `chunks` | The `.js` files of `.web/build/client/assets`. |\n| `web_dir` | The regular files under `.web` outside `node_modules` (build output, compiled pages, templates). |\n| `node_modules` | The regular files under `.web/node_modules`. Symlinks are neither followed nor counted, here and in `web_dir`. |\n\nThe harness compresses each file on its own, gzip at level 9 (`mtime=0`) and\nbrotli at quality 11. Reflex 0.9 writes `.gz` sidecars next to the build's files\n(`.br` and `.zst` too when configured) and 0.8.23 writes none, so sidecars are\nnever measured, only summed into the extra data's `sidecar_bytes`. Each sample's\nextra data also holds the per-file breakdown `files`: `raw`, `gzip`, `brotli` and\n`initial` for each file of the client build, keyed by its path with the content\nhash of names in `assets/` replaced (`assets/chunk-5KNZJZUH-q9CrfzJj.js` becomes\n`assets/chunk-5KNZJZUH-HASH.js`; `#2` marks a second name that differed only in\nits hash), plus `initial_files` in page order, `html` (the page parsed),\n`reflex_version`, `fixture_hash` (the playground's committed `.content-hash`,\nthe hash the result series are keyed on and that CI keeps current; an\nuncommitted playground edit shows in the subject's `dirty` flag instead),\n`bun_lock` (the hash of `.web/bun.lock`) and the `compressors`' versions. Apps\nwith a `frontend_path` are not s\n\n<!-- [TRUNCATED AT 50KB] -->","packages/reflex-build-sdk/README.md":"# reflex-build-sdk\n\nPython client for the [Reflex Build](https://build.reflex.dev) API, with synchronous and asynchronous interfaces.\n\nInstall it with the HTTP library the client should send requests with:\n\n```bash\npip install \"reflex-build-sdk[httpx2]\"   # ReflexBuild and AsyncReflexBuild\npip install \"reflex-build-sdk[aiohttp]\"  # AsyncReflexBuild only\npip install \"reflex-build-sdk[httpx]\"    # ReflexBuild and AsyncReflexBuild\n```\n\nWithout any of them, pass the client a [transport](#transports) of your own.\n\n```python\nfrom reflex_build_sdk import ReflexBuild\n\nwith ReflexBuild() as client:\n    me = client.auth.me()\n    print(me.email, me.tier)\n```\n\n```python\nfrom reflex_build_sdk import AsyncReflexBuild\n\nasync with AsyncReflexBuild() as client:\n    me = await client.auth.me()\n```\n\n## Apps and projects\n\n```python\nfrom reflex_build_sdk import ReflexBuild\n\nwith ReflexBuild() as client:\n    projects = client.projects.search(\"default\")\n    project = projects[0] if projects else client.projects.create(\"default\")\n    app = client.apps.create(\"dashboard\", project_id=project.id)\n    client.apps.secrets.set(app.id, {\"OPENAI_API_KEY\": \"sk-...\"})\n\n    for deployment in client.apps.history(app.id):\n        print(deployment.status, deployment.url)\n\n    for record in client.apps.logs(app.id, search=\"error\"):\n        print(record.timestamp, record.message)\n```\n\n`client.apps` lists, creates, renames, moves, starts, stops, pauses, scales, rolls back and deletes apps, changes their settings, and reads their status, running deployment, deployment history and runtime logs; `client.apps.secrets` manages their secrets. `client.projects` lists, searches, creates, renames and deletes projects and reads their audit logs, with `projects.roles` (including custom roles), `projects.members` and `projects.teams` for access control. `AsyncReflexBuild` has the same methods as coroutines, with `logs` as an async iterator.\n\n### Custom domains\n\n```python\nfor record in client.apps.domains.add(app.id, \"app.example.com\").values():\n    print(record.type, record.name, record.value)\n\ndomain = client.apps.domains.get(app.id)\nprint(domain.status, domain.status_detail)\n```\n\n`domains.add` returns the DNS records to create, and `domains.get` checks them and reports whether the domain is ready to serve the app. Custom domains need the Pro or Enterprise plan.\n\n## Deploying\n\n```python\nfrom reflex_build_sdk import DeploymentFailedError, ReflexBuild\n\nwith ReflexBuild() as client:\n    urls = client.apps.reserve_hostname(app.id, app.name)\n    # Export the app against urls.frontend_url and urls.backend_url, e.g. with\n    # `reflex export`, producing backend.zip and frontend.zip.\n    deployment_id = client.deployments.create(\n        app.id,\n        backend=\"backend.zip\",\n        frontend=\"frontend.zip\",\n        regions={\"sjc\": 1},\n        on_upload_progress=lambda sent, total: print(f\"{sent}/{total} bytes\"),\n    )\n    try:\n        report = client.deployments.wait(deployment_id, on_status=print, timeout=900)\n    except DeploymentFailedError as error:\n        print(error.report.reason, error.report.guidance)\n        print(error.report.build_log_excerpt)\n        raise\n```\n\n`deployments.create` streams the archives straight to storage, then submits the deployment. `deployments.wait` returns the deployment's report once it is running, or awaiting approval (`report.status == \"AwaitingApproval\"`), and raises `DeploymentFailedError` if it fails. `deployments.status`, `report` and `build_logs` read a deployment's progress, and `regions` and `vm_types` list what can be deployed to.\n\n### Environments\n\nGive an app a pipeline of a dev and a production environment:\n\n```python\npipeline = client.apps.environments.enable(app.id)\nproduction_id = pipeline.production_environment_id\n```\n\nAn app that has a pipeline already is read rather than enabled again, which fails:\n\n```python\ndev, production = client.apps.environments.list(app.id)\nproduction_id = production.id\n```\n\nDeployments go to the first environment, and later ones run a version promoted from the one before:\n\n```python\ndeployment_id = client.deployments.create(\n    app.id, backend=\"backend.zip\", frontend=\"frontend.zip\"\n)\nclient.deployments.wait(deployment_id)\npromotion = client.apps.environments.promote(app.id, production_id)\nclient.deployments.wait(promotion.deployment_id)\n```\n\nEach environment has its own secrets and URL, and production keeps the app's own id and history. `environments.create`, `update`, `reorder`, `copy_missing_secrets` and `delete` manage the rest of the pipeline. Pipelines need the Enterprise plan.\n\n### Managed database\n\n```python\ndatabase = client.apps.database.create(app.id)\nprint(database.masked_connection_string)\n```\n\n`client.apps.database` creates a Postgres database for an app, shared by all of its environments, and sets its connection strings as secrets, `DATABASE_URL` among them, which each environment picks up on its next deployment. Creating or deleting a database needs a token with full access, which `reflex login` tokens are not, and an app with its own `DATABASE_URL` secret is refused.\n\n### Signing users in\n\n```python\nclient.apps.sign_in.enable(app.id)\nclient.apps.sign_in.set_audience(app.id, \"invited\")\nclient.apps.sign_in.invite(app.id, \"someone@example.com\")\n```\n\n`client.apps.sign_in` lets an app's users sign in with their Reflex accounts, through `rxe.AuthPlugin` from `reflex-enterprise`. It sets the app's sign-in settings as secrets, which take effect when the app is next deployed with `rxe.AuthPlugin`, chooses who may sign in, and lists, exports and blocks the app's users. Restricting who may sign in and inviting addresses need the Pro or Enterprise plan. Changing sign-in needs a token with full access; tokens from `reflex login` are refused.\n\n### Third-party connections\n\n```python\n# Inside a deployed app, which is started with its own access token.\nwith ReflexBuild() as client:\n    token = client.apps.connections.credential(app_id, \"openai\").access_token\n    # ... and for one of the app's users:\n    token = client.apps.connections.credential(\n        app_id, \"openai\", end_user=user_id\n    ).access_token\n```\n\n`client.apps.connections` calls third-party services an app is connected to without the app holding their keys: Reflex Build stores the credentials and hands out a live one per call, so read one for each call rather than storing it. `connect_link` starts a connection and returns the page to send someone to, `status` and `list` report what is connected, and `disconnect` ends it. A connection belongs either to the app or to one of its users, named with `end_user`. These need the app's own token, so a client built with no arguments inside a deployed app is already the right one.\n\n## Authentication\n\nThe client uses the `token` argument, or the `REFLEX_ACCESS_TOKEN` environment variable when none is passed.\n\nTo log in through the browser:\n\n```python\nimport webbrowser\n\nfrom reflex_build_sdk import ReflexBuild\n\nwith ReflexBuild() as client:\n    login = client.auth.begin_login()\n    print(f\"Approve the login at {login.url}\")\n    webbrowser.open(login.url)\n    token = client.auth.finish_login(login, timeout=600)\n\nwith ReflexBuild(token=token) as client:\n    print(client.auth.me().email)\n```\n\n`client.auth.tokens.revoke_self()` revokes the client's own token, which any token may do. Create a token for CI with `client.auth.tokens.create(\"ci\", expires_in_days=30)`, whose `.token` holds the value, and rotate or revoke one with `client.auth.tokens.refresh(token)`, whose `.token` holds the new value, and `client.auth.tokens.revoke(token)`. If a refresh answers `previous_revoked=False`, the old token is still live and needs revoking. Managing other tokens needs a token with full access, which `reflex login` tokens are not.\n\n`client.usage.balance()` reports how much of the organization's plan allowance is used, and `client.usage.history()` iterates over its charges and credits.\n\n### Pointing at another deployment\n\nThe client sends its requests to `https://build.reflex.dev`, or to the `base_url` argument, the `REFLEX_BUILD_BACKEND_URL` environment variable or `REFLEX_CLOUD_BACKEND_URL`, in that order. `begin_login` builds its approval URL the same way, from `ui_url`, `REFLEX_BUILD_URL` or `REFLEX_CLOUD_URL`, and falls back to the client's `base_url`. `reflex-hosting-cli` reads only the `REFLEX_CLOUD_*` names, so set those too for `reflex deploy` to reach the same deployment.\n\n## Security reviews\n\n```python\nreview_id = client.security_reviews.submit(\"source.zip\")\nresult = client.security_reviews.wait(review_id, timeout=600)\nfor violation in result.violations:\n    print(violation.severity, violation.file_path, violation.line, violation.message)\n```\n\nSecurity reviews need the Pro or Enterprise plan.\n\n## Google Cloud\n\nApps can run on an organization's own Google Cloud instead of Reflex Build:\n\n```python\nstatus = client.providers.gcp_status(client.auth.me().org_id)\nif status.configured and status.allowed:\n    client.apps.set_provider(app.id, \"gcp\")\n    client.apps.set_instance_bounds(app.id, min_instances=1, max_instances=10)\n```\n\nRunning on Google Cloud needs the Enterprise plan. `client.apps.set_full_deploy` also serves an app's frontend from Google Cloud, and `client.providers.cloud_run_manifest()` returns the Dockerfile and script to deploy to Cloud Run yourself.\n\nOrganization admins connect Google Cloud projects with a service account key:\n\n```python\nwith open(\"key.json\") as key_file:\n    client.providers.connect_gcp(\n        client.auth.me().org_id,\n        service_account_key=key_file.read(),\n        project_number=\"123456789012\",\n        region=\"us-central1\",\n    )\n```\n\n`client.providers.gcp_connections` adds, updates, verifies and removes further projects, rotates their keys and chooses the default, and `client.providers.disconnect_gcp` removes them all. These need a token with full access.\n\n## Errors\n\nEvery exception derives from `reflex_build_sdk.ReflexBuildError`. Error responses raise a subclass of `APIStatusError` matching the status code (`AuthenticationError`, `NotFoundError`, ...), carrying `status_code`, the server's `detail`, the `code` naming the condition where the API names one (e.g. `\"not_connected\"`), and the `request_id` to quote to support. Failed requests are retried up to `max_retries` times when repeating them cannot apply them twice: requests that never reached the server or were turned away with 408 or 429, and requests that are harmless to repeat (`GET`, `HEAD`, `OPTIONS` and `PUT` requests, and calls such as `apps.environments.update` that settle on the same result) that timed out, lost their connection, or got a 500, 502, 503 or 504 response.\n\n## Transports\n\n`AsyncReflexBuild` sends requests with the first installed of [aiohttp](https://docs.aiohttp.org), [httpx2](https://github.com/pydantic/httpx2) and [httpx](https://www.python-httpx.org), and `ReflexBuild` with httpx2, or httpx if httpx2 is not installed. Pass a transport from `reflex_build_sdk.transports` to configure the HTTP client, e.g. for proxies, or to pick the HTTP library:\n\n```python\nimport aiohttp\nimport httpx2\nfrom reflex_build_sdk import AsyncReflexBuild, ReflexBuild\nfrom reflex_build_sdk.transports import (\n    AiohttpTransport,\n    AsyncHttpx2Transport,\n    Httpx2Transport,\n)\n\n# Reads HTTP_PROXY, HTTPS_PROXY and NO_PROXY from the environment.\nasync with aiohttp.ClientSession(trust_env=True) as session:\n    async with AsyncReflexBuild(transport=AiohttpTransport(session)) as client:\n        ...\n\nclient = AsyncReflexBuild(transport=AsyncHttpx2Transport())\nclient = ReflexBuild(\n    transport=Httpx2Transport(httpx2.Client(proxy=\"http://proxy:8080\"))\n)\n```\n\nTo use another HTTP library, implement the `Transport` or `AsyncTransport` protocol.\n\nTo wrap the synchronous SDK's default transport without choosing an HTTP library,\ncall `reflex_build_sdk.transports.default_transport()`. It selects httpx2 when\ninstalled, otherwise httpx. Close the returned transport when finished; clients\nleave explicitly supplied transports open.\n","packages/reflex-build-sdk/openapi.json":"{\n  \"components\": {\n    \"schemas\": {\n      \"AccessJson\": {\n        \"description\": \"Serialized token access stored on the token row and in the AuthZ cache.\",\n        \"properties\": {\n          \"permissions\": {\n            \"additionalProperties\": {\n              \"type\": \"string\"\n            },\n            \"description\": \"Each permission the token holds, by key (`account`, `project`, `app`, `thread`), mapped to how much of it -- `none`, `read` or `write`.\",\n            \"title\": \"Permissions\",\n            \"type\": \"object\"\n          },\n          \"projects\": {\n            \"anyOf\": [\n              {\n                \"const\": \"all\",\n                \"type\": \"string\"\n              },\n              {\n                \"items\": {\n                  \"type\": \"string\"\n                },\n                \"type\": \"array\"\n              }\n            ],\n            \"description\": \"Which projects the project-scoped permissions above apply to: `all`, or the ids they are confined to.\",\n            \"title\": \"Projects\"\n          }\n        },\n        \"required\": [\n          \"permissions\",\n          \"projects\"\n        ],\n        \"title\": \"AccessJson\",\n        \"type\": \"object\"\n      },\n      \"AdminAppListEntry\": {\n        \"additionalProperties\": true,\n        \"description\": \"One row of the instance-admin app table.\\n\\nThe columns are fixed; what the request varies is the filter and the sort.\\nDeleted apps and projects are listed and flagged rather than hidden, since\\ntheir deployment rows outlive them and stay listed.\",\n        \"properties\": {\n          \"app_description\": {\n            \"description\": \"Free text the owner set.\",\n            \"title\": \"App Description\",\n            \"type\": \"string\"\n          },\n          \"app_id\": {\n            \"description\": \"The app's id.\",\n            \"format\": \"uuid\",\n            \"title\": \"App Id\",\n            \"type\": \"string\"\n          },\n          \"app_name\": {\n            \"description\": \"The app's name.\",\n            \"title\": \"App Name\",\n            \"type\": \"string\"\n          },\n          \"created_at\": {\n            \"description\": \"When the app row was created.\",\n            \"format\": \"date-time\",\n            \"title\": \"Created At\",\n            \"type\": \"string\"\n          },\n          \"deployment_count\": {\n            \"description\": \"Every deployment this app has ever had, on-prem rows included.\",\n            \"title\": \"Deployment Count\",\n            \"type\": \"integer\"\n          },\n          \"deployment_hostname\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The serving label it was given, nullable on the row and so absent independently of the deployment.\",\n            \"title\": \"Deployment Hostname\"\n          },\n          \"deployment_status\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"That deployment's status, null wherever `latest_deployment_id` is, as is `deployment_ts`. The two address fields between them are nullable on the deployment row itself, so either can be null while this is set.\",\n            \"title\": \"Deployment Status\"\n          },\n          \"deployment_ts\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"When that deployment's row was created, which a start or a rollback does not move.\",\n            \"title\": \"Deployment Ts\"\n          },\n          \"deployment_url\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The frontend a browser is pointed at. Null on a row whose serving host was never resolved -- a legacy row carries a bare `deployment_hostname` with no url -- so this is absent independently of the deployment.\",\n            \"title\": \"Deployment Url\"\n          },\n          \"full_deploy\": {\n            \"description\": \"Whether the whole app runs on the provider, frontend included, rather than serving its frontend from Reflex's CDN.\",\n            \"title\": \"Full Deploy\",\n            \"type\": \"boolean\"\n          },\n          \"is_deleted\": {\n            \"description\": \"Whether the app is soft-deleted.\",\n            \"title\": \"Is Deleted\",\n            \"type\": \"boolean\"\n          },\n          \"latest_deployment_id\": {\n            \"anyOf\": [\n              {\n                \"format\": \"uuid\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The app's current deployment -- a live or in-progress one before a terminal one, newest first, production identity only. Null for an app that has never deployed, and for one whose deployments are all on-prem, which this skips while `deployment_count` still counts them.\",\n            \"title\": \"Latest Deployment Id\"\n          },\n          \"org_id\": {\n            \"description\": \"The organization that owns the project.\",\n            \"format\": \"uuid\",\n            \"title\": \"Org Id\",\n            \"type\": \"string\"\n          },\n          \"org_name\": {\n            \"description\": \"That organization's name.\",\n            \"title\": \"Org Name\",\n            \"type\": \"string\"\n          },\n          \"project_id\": {\n            \"description\": \"The project the app is in.\",\n            \"format\": \"uuid\",\n            \"title\": \"Project Id\",\n            \"type\": \"string\"\n          },\n          \"project_is_deleted\": {\n            \"description\": \"Whether the project is soft-deleted. Deleting a project only queues its apps' own delete, so inside that window this is the app's only marker.\",\n            \"title\": \"Project Is Deleted\",\n            \"type\": \"boolean\"\n          },\n          \"project_name\": {\n            \"description\": \"That project's name.\",\n            \"title\": \"Project Name\",\n            \"type\": \"string\"\n          },\n          \"provider\": {\n            \"description\": \"Where the app deploys: Reflex's own hosting, or the org's cloud account.\",\n            \"title\": \"Provider\",\n            \"type\": \"string\"\n          },\n          \"vm_type_name\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Read from the machine rather than the deployment row: a size-scale rewrites the machines and leaves the row's own vmtype_id at the size it was deployed at.\",\n            \"title\": \"Vm Type Name\"\n          }\n        },\n        \"required\": [\n          \"app_id\",\n          \"app_name\",\n          \"app_description\",\n          \"provider\",\n          \"full_deploy\",\n          \"is_deleted\",\n          \"created_at\",\n          \"project_id\",\n          \"project_name\",\n          \"project_is_deleted\",\n          \"org_id\",\n          \"org_name\",\n          \"latest_deployment_id\",\n          \"deployment_status\",\n          \"deployment_url\",\n          \"deployment_hostname\",\n          \"deployment_ts\",\n          \"vm_type_name\",\n          \"deployment_count\"\n        ],\n        \"title\": \"AdminAppListEntry\",\n        \"type\": \"object\"\n      },\n      \"AdminAppMoveResponse\": {\n        \"description\": \"What the move did, in the shape the app route's own move answers.\\n\\nThe three repository fields come from ``move_shortfall_payload``, which both\\nmove paths share so they cannot come to spell a key differently -- a reader\\ntakes an absent key for a move that cost nothing. The destination is named\\n``target_project_id`` here and ``project_id`` there, which is the one\\ndifference and is what each has always answered with.\",\n        \"properties\": {\n          \"app_id\": {\n            \"description\": \"The app that moved.\",\n            \"format\": \"uuid\",\n            \"title\": \"App Id\",\n            \"type\": \"string\"\n          },\n          \"copied_integrations\": {\n            \"description\": \"The integrations copied across to the destination project.\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"title\": \"Copied Integrations\",\n            \"type\": \"array\"\n          },\n          \"message\": {\n            \"description\": \"What the move did, for a reader.\",\n            \"title\": \"Message\",\n            \"type\": \"string\"\n          },\n          \"permissions_repointed\": {\n            \"description\": \"Whether the app's authorization tuples were repointed at the destination project. False leaves who can reach the app answered by the *source* project until the periodic reconciler heals it -- the move landed, so this is reported rather than raised.\",\n            \"title\": \"Permissions Repointed\",\n            \"type\": \"boolean\"\n          },\n          \"repo_token_notices\": {\n            \"description\": \"The two lists above said in sentences, for showing somebody. Free text; read the lists to branch.\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"title\": \"Repo Token Notices\",\n            \"type\": \"array\"\n          },\n          \"repo_tokens_failed\": {\n            \"description\": \"Threads whose credential the hand-over could not write. The move landed, so these are reported rather than raised -- and nothing revisits them: those apps cannot push until somebody reconnects.\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"title\": \"Repo Tokens Failed\",\n            \"type\": \"array\"\n          },\n          \"repo_tokens_withheld\": {\n            \"description\": \"Threads whose repository credential was deliberately not handed over, because the destination is not entitled to it.\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"title\": \"Repo Tokens Withheld\",\n            \"type\": \"array\"\n          },\n          \"target_project_id\": {\n            \"description\": \"Where it moved to. Named `project_id` on the app route's own move, which is the one difference between the two shapes and is what each has always answered with.\",\n            \"format\": \"uuid\",\n            \"title\": \"Target Project Id\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"message\",\n          \"app_id\",\n          \"target_project_id\",\n          \"copied_integrations\",\n          \"repo_tokens_withheld\",\n          \"repo_tokens_failed\",\n          \"repo_token_notices\",\n          \"permissions_repointed\"\n        ],\n        \"title\": \"AdminAppMoveResponse\",\n        \"type\": \"object\"\n      },\n      \"AdminDeploymentListEntry\": {\n        \"additionalProperties\": true,\n        \"description\": \"One row of the instance-admin deployment table.\\n\\nFixed columns, for the reason the app table's are: the request varies the\\nfilter and the sort.\",\n        \"properties\": {\n          \"app_id\": {\n            \"description\": \"The app it belongs to.\",\n            \"format\": \"uuid\",\n            \"title\": \"App Id\",\n            \"type\": \"string\"\n          },\n          \"app_is_deleted\": {\n            \"description\": \"Whether the app is soft-deleted.\",\n            \"title\": \"App Is Deleted\",\n            \"type\": \"boolean\"\n          },\n          \"app_name\": {\n            \"description\": \"That app's name.\",\n            \"title\": \"App Name\",\n            \"type\": \"string\"\n          },\n          \"deployed_by_email\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"That account's address, where it still has one.\",\n            \"title\": \"Deployed By Email\"\n          },\n          \"deployed_by_id\": {\n            \"anyOf\": [\n              {\n                \"format\": \"uuid\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Who submitted it, null where that account has since been purged -- as are the two fields below it.\",\n            \"title\": \"Deployed By Id\"\n          },\n          \"deployed_by_username\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"And its display name, not a handle: derived from the address for a person, and the name an org admin chose for a service account.\",\n            \"title\": \"Deployed By Username\"\n          },\n          \"deployment_id\": {\n            \"description\": \"The deployment's id.\",\n            \"format\": \"uuid\",\n            \"title\": \"Deployment Id\",\n            \"type\": \"string\"\n          },\n          \"deployment_ts\": {\n            \"description\": \"When the row was created. Not when it went live: a start or a rollback re-parks a row that may be weeks old.\",\n            \"format\": \"date-time\",\n            \"title\": \"Deployment Ts\",\n            \"type\": \"string\"\n          },\n          \"description\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The submitter's changelog note for this deployment, not the app's own description.\",\n            \"title\": \"Description\"\n          },\n          \"hostname\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The serving label it was given.\",\n            \"title\": \"Hostname\"\n          },\n          \"persist\": {\n            \"description\": \"Exempt from idle suspension, so the app keeps a machine running with no traffic.\",\n            \"title\": \"Persist\",\n            \"type\": \"boolean\"\n          },\n          \"project_id\": {\n            \"description\": \"The project the app is in.\",\n            \"format\": \"uuid\",\n            \"title\": \"Project Id\",\n            \"type\": \"string\"\n          },\n          \"project_is_deleted\": {\n            \"description\": \"Deleting a project only queues its apps' soft-delete, so inside that window this is a row's only marker.\",\n            \"title\": \"Project Is Deleted\",\n            \"type\": \"boolean\"\n          },\n          \"python_version\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The Python version the build reported, which chose its base image.\",\n            \"title\": \"Python Version\"\n          },\n          \"reflex_version\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"What the app was built against, as the build reported it.\",\n            \"title\": \"Reflex Version\"\n          },\n          \"region_names\": {\n            \"description\": \"Where the deployment's machines are, empty if it has none.\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"title\": \"Region Names\",\n            \"type\": \"array\"\n          },\n          \"status\": {\n            \"description\": \"Where the deployment stands. This listing filters on nothing, so it carries every status the codebase writes: serving (`Running`, `Paused`, `Error: Out of Memory`), in flight (`Pending`, `AwaitingApproval`), never run (`Rejected`, `Superseded`, `Expired`) and finished (`Failed`, `Stopped`, `Historical`). The column is unconstrained text, so a legacy row can hold a value nothing writes any more -- `Removed` is the one still recognised, and an unlisted value is not a client error.\",\n            \"title\": \"Status\",\n            \"type\": \"string\"\n          },\n          \"strategy\": {\n            \"description\": \"How the rollout was made, as submitted: `immediate`, `rolling`, `bluegreen` or `canary`. `rolling` and `canary` are accepted on Fly only, and take the blue-green path.\",\n            \"title\": \"Strategy\",\n            \"type\": \"string\"\n          },\n          \"url\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The frontend a browser is pointed at.\",\n            \"title\": \"Url\"\n          },\n          \"vm_type_cpu\": {\n            \"anyOf\": [\n              {\n                \"type\": \"number\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"That machine's CPU count.\",\n            \"title\": \"Vm Type Cpu\"\n          },\n          \"vm_type_name\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Read from the machine rather than the row: a size-scale rewrites the machines and leaves `vmtype_id` at the size the deployment was made at. Null where no machine answered.\",\n            \"title\": \"Vm Type Name\"\n          },\n          \"vm_type_ram\": {\n            \"anyOf\": [\n              {\n                \"type\": \"number\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"That machine's memory, in GB, as the catalog stores it -- a 4096 MB machine reads 4.096.\",\n            \"title\": \"Vm Type Ram\"\n          },\n          \"vmtype_id\": {\n            \"description\": \"The machine size the row was deployed at, as stored. `GET /deployments/vm_types` resolves a catalog size and not the `custom-c<cpu>m<ram_mb>` id an explicit cpu/memory deploy mints, nor on-prem's `prem`; the `vm_type_*` fields below carry the shape either way.\",\n            \"title\": \"Vmtype Id\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"deployment_id\",\n          \"app_id\",\n          \"app_name\",\n          \"app_is_deleted\",\n          \"project_id\",\n          \"project_is_deleted\",\n          \"status\",\n          \"url\",\n          \"hostname\",\n          \"deployment_ts\",\n          \"reflex_version\",\n          \"python_version\",\n          \"persist\",\n          \"strategy\",\n          \"description\",\n          \"vmtype_id\",\n          \"vm_type_name\",\n          \"vm_type_ram\",\n          \"vm_type_cpu\",\n          \"deployed_by_id\",\n          \"deployed_by_email\",\n          \"deployed_by_username\",\n          \"region_names\"\n        ],\n        \"title\": \"AdminDeploymentListEntry\",\n        \"type\": \"object\"\n      },\n      \"AppAudience\": {\n        \"description\": \"Who an app will sign in.\\n\\nOnly ``PUBLIC`` admits somebody with no standing at all, which is why it is\\nthe one mode a change *to* needs no session sweep: every other value can\\nonly take admission away from somebody who holds it now, and a mode that\\nrefuses the next sign-in while leaving the current one running is not the\\ncontrol it says it is.\\n\\n``MEMBERS`` and ``INVITED`` are not ordered against each other. An invited\\nstranger is not a member, and a member is not necessarily invited, so\\n\\\"narrower\\\" is not a total order here and nothing tries to make it one --\\nwhich is why the sweep asks what is being moved *to* rather than comparing\\nthe two.\",\n        \"enum\": [\n          \"public\",\n          \"members\",\n          \"invited\",\n          \"owner_only\"\n        ],\n        \"title\": \"AppAudience\",\n        \"type\": \"string\"\n      },\n      \"AppAudienceChangedResponse\": {\n        \"description\": \"An audience change, and the sessions the narrowing ended.\\n\\n``changed`` is false where the mode was already the one asked for.\\n``revoked_sessions`` is a count and ``sweep_failed`` says whether it ran,\\nfor the reason a block's are.\",\n        \"properties\": {\n          \"audience\": {\n            \"description\": \"The mode the app is on now.\",\n            \"title\": \"Audience\",\n            \"type\": \"string\"\n          },\n          \"changed\": {\n            \"description\": \"False where it was already the one asked for.\",\n            \"title\": \"Changed\",\n            \"type\": \"boolean\"\n          },\n          \"revoked_sessions\": {\n            \"description\": \"How many sessions the narrowing ended. Zero where the sweep failed as well as where there were none -- `sweep_failed` tells those apart, for the reason a block's does.\",\n            \"title\": \"Revoked Sessions\",\n            \"type\": \"integer\"\n          },\n          \"sweep_failed\": {\n            \"description\": \"Whether ending the sessions the new mode refuses is still owed, which is weaker than any being left running: the sweep is one bulk call, so a failure leaves how many there were unknown -- an app nobody was signed in to reports this too. The mode is committed before the sweep, so the change applied either way. Whatever was signed in ends at the next refresh, and setting the mode again sweeps them.\",\n            \"title\": \"Sweep Failed\",\n            \"type\": \"boolean\"\n          }\n        },\n        \"required\": [\n          \"audience\",\n          \"changed\",\n          \"revoked_sessions\",\n          \"sweep_failed\"\n        ],\n        \"title\": \"AppAudienceChangedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAudienceResponse\": {\n        \"description\": \"Who an app signs in, and -- for a caller entitled to it -- who is invited.\\n\\n``audience`` is null where the stored mode is one this deployment does not\\nknow -- which refuses every sign-in, so it is not ``public``.\\n\\n``invites`` is null rather than absent for a caller who may read the mode\\nand not the list, which is a set of email addresses. One shape with a\\nnullable field rather than two shapes, because a caller cannot discriminate\\na union whose members differ only by a key being missing: an empty list and\\na withheld list read identically, and \\\"there is nobody invited\\\" is the\\nopposite answer to \\\"you may not see who is\\\".\",\n        \"properties\": {\n          \"audience\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Who the app signs in. Null where the stored mode is one this deployment does not know -- which refuses every sign-in, so it is not `public`.\",\n            \"title\": \"Audience\"\n          },\n          \"invites\": {\n            \"anyOf\": [\n              {\n                \"items\": {\n                  \"$ref\": \"#/components/schemas/AppAuthInviteResponse\"\n                },\n                \"type\": \"array\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Who is invited, or null for a caller who may read the mode and not the list. Nullable rather than absent, because an empty list and a withheld one read identically -- and `there is nobody invited` is the opposite answer to `you may not see who is`.\",\n            \"title\": \"Invites\"\n          }\n        },\n        \"required\": [\n          \"audience\",\n          \"invites\"\n        ],\n        \"title\": \"AppAudienceResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthAbsentResponse\": {\n        \"description\": \"An app the broker does not sign users in for.\\n\\n``client_enabled`` is reported either way: the client row can outlive the\\nkeys, so a half-torn-down app is visible as one rather than as clean.\",\n        \"properties\": {\n          \"client_enabled\": {\n            \"description\": \"Whether the broker will complete a login for this app. Written separately from the keys, so an app carrying them with the client row disabled refuses every sign-in -- which is why this is reported either way rather than implied by `has_auth`.\",\n            \"title\": \"Client Enabled\",\n            \"type\": \"boolean\"\n          },\n          \"has_auth\": {\n            \"const\": false,\n            \"description\": \"Always false on this body; the configured answer is the other member of the union.\",\n            \"title\": \"Has Auth\",\n            \"type\": \"boolean\"\n          },\n          \"kind\": {\n            \"description\": \"Which sign-in this app has, which `has_auth` alone cannot say: `none` is an app that signs nobody in, `managed` is the broker's, and `connected` is the app's own identity provider -- so a client offered \\\"set up sign-in\\\" can tell an app with nothing from one whose provider has to be disconnected first.\",\n            \"enum\": [\n              \"none\",\n              \"managed\",\n              \"connected\"\n            ],\n            \"title\": \"Kind\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"has_auth\",\n          \"client_enabled\",\n          \"kind\"\n        ],\n        \"title\": \"AppAuthAbsentResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthConfiguredResponse\": {\n        \"description\": \"An app the broker signs users in for, and as whom.\\n\\n``has_auth`` is what the app's own environment holds and\\n``client_enabled`` whether the broker will complete a login for it; an app\\ncarrying the keys with no enabled client row refuses every sign-in.\",\n        \"properties\": {\n          \"client_enabled\": {\n            \"description\": \"Whether the broker will complete a login for this app. Written separately from the keys, so an app carrying them with the client row disabled refuses every sign-in -- which is why this is reported either way rather than implied by `has_auth`.\",\n            \"title\": \"Client Enabled\",\n            \"type\": \"boolean\"\n          },\n          \"client_id\": {\n            \"description\": \"The app's OAuth client id, which is the app's own id. It is also the audience its identity tokens carry, so one app's token fails another app's check.\",\n            \"title\": \"Client Id\",\n            \"type\": \"string\"\n          },\n          \"has_auth\": {\n            \"const\": true,\n            \"description\": \"Always true on this body. It says what the app's own environment holds, which `client_enabled` beside it does not.\",\n            \"title\": \"Has Auth\",\n            \"type\": \"boolean\"\n          },\n          \"issuer\": {\n            \"description\": \"The OIDC issuer the app's client validates against. One per deployment, shared by every app -- what separates them is the audience, which is the app's own id.\",\n            \"title\": \"Issuer\",\n            \"type\": \"string\"\n          },\n          \"kind\": {\n            \"description\": \"Which sign-in this app has, which `has_auth` alone cannot say: `none` is an app that signs nobody in, `managed` is the broker's, and `connected` is the app's own identity provider -- so a client offered \\\"set up sign-in\\\" can tell an app with nothing from one whose provider has to be disconnected first.\",\n            \"enum\": [\n              \"none\",\n              \"managed\",\n              \"connected\"\n            ],\n            \"title\": \"Kind\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"has_auth\",\n          \"issuer\",\n          \"client_id\",\n          \"client_enabled\",\n          \"kind\"\n        ],\n        \"title\": \"AppAuthConfiguredResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthDeprovisionedResponse\": {\n        \"description\": \"A deprovisioning. ``deleted`` is false where there was nothing to take.\\n\\n``kind`` is what the app holds now, and is what separates the two ways\\n``deleted`` is false: an app that had no sign-in at all reads ``none``, and\\none carrying its own identity provider reads ``connected`` -- which this\\nroute deliberately does not touch, so the remedy is to disconnect that\\nrather than to retry here.\",\n        \"properties\": {\n          \"deleted\": {\n            \"description\": \"Whether this call took anything. False two ways, which `kind` separates: an app that had no sign-in at all, and one carrying its own identity provider, which this route deliberately does not touch.\",\n            \"title\": \"Deleted\",\n            \"type\": \"boolean\"\n          },\n          \"kind\": {\n            \"description\": \"Which sign-in this app has, which `has_auth` alone cannot say: `none` is an app that signs nobody in, `managed` is the broker's, and `connected` is the app's own identity provider -- so a client offered \\\"set up sign-in\\\" can tell an app with nothing from one whose provider has to be disconnected first.\",\n            \"enum\": [\n              \"none\",\n              \"managed\",\n              \"connected\"\n            ],\n            \"title\": \"Kind\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"deleted\",\n          \"kind\"\n        ],\n        \"title\": \"AppAuthDeprovisionedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthInviteCreatedResponse\": {\n        \"description\": \"One invited address, and whether *this* request is what added it.\\n\\n``created`` does not belong on the listing entry: it is a fact about one\\nrequest, and a row in a list has no request to be about.\",\n        \"properties\": {\n          \"created\": {\n            \"description\": \"Whether this request added the address. False means it was already invited and nothing changed, which the 200 rather than 201 also says.\",\n            \"title\": \"Created\",\n            \"type\": \"boolean\"\n          },\n          \"created_at\": {\n            \"description\": \"When it was invited.\",\n            \"format\": \"date-time\",\n            \"title\": \"Created At\",\n            \"type\": \"string\"\n          },\n          \"email\": {\n            \"description\": \"The invited address, folded -- which is the form the list is keyed by.\",\n            \"title\": \"Email\",\n            \"type\": \"string\"\n          },\n          \"redeemed\": {\n            \"description\": \"The same fact as a flag, for a client that only needs the yes or no.\",\n            \"title\": \"Redeemed\",\n            \"type\": \"boolean\"\n          },\n          \"redeemed_at\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"When somebody first signed in on it; null while nobody has.\",\n            \"title\": \"Redeemed At\"\n          }\n        },\n        \"required\": [\n          \"email\",\n          \"created_at\",\n          \"redeemed_at\",\n          \"redeemed\",\n          \"created\"\n        ],\n        \"title\": \"AppAuthInviteCreatedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthInviteResponse\": {\n        \"description\": \"One invited address, and whether anybody has signed in on it.\",\n        \"properties\": {\n          \"created_at\": {\n            \"description\": \"When it was invited.\",\n            \"format\": \"date-time\",\n            \"title\": \"Created At\",\n            \"type\": \"string\"\n          },\n          \"email\": {\n            \"description\": \"The invited address, folded -- which is the form the list is keyed by.\",\n            \"title\": \"Email\",\n            \"type\": \"string\"\n          },\n          \"redeemed\": {\n            \"description\": \"The same fact as a flag, for a client that only needs the yes or no.\",\n            \"title\": \"Redeemed\",\n            \"type\": \"boolean\"\n          },\n          \"redeemed_at\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"When somebody first signed in on it; null while nobody has.\",\n            \"title\": \"Redeemed At\"\n          }\n        },\n        \"required\": [\n          \"email\",\n          \"created_at\",\n          \"redeemed_at\",\n          \"redeemed\"\n        ],\n        \"title\": \"AppAuthInviteResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthProvisionedResponse\": {\n        \"description\": \"A provisioning. ``created`` is false where it was already there.\\n\\nCarries ``client_enabled`` like the read does, and for its reason: the two\\nhalves are written separately, so a provision that wrote the keys and left\\nthe client row disabled would otherwise answer exactly as a working one.\",\n        \"properties\": {\n          \"client_enabled\": {\n            \"description\": \"Whether the broker will complete a login for this app. Written separately from the keys, so an app carrying them with the client row disabled refuses every sign-in -- which is why this is reported either way rather than implied by `has_auth`.\",\n            \"title\": \"Client Enabled\",\n            \"type\": \"boolean\"\n          },\n          \"client_id\": {\n            \"description\": \"The app's OAuth client id, which is the app's own id. It is also the audience its identity tokens carry, so one app's token fails another app's check.\",\n            \"title\": \"Client Id\",\n            \"type\": \"string\"\n          },\n          \"created\": {\n            \"description\": \"Whether this call provisioned it; false where it was already there.\",\n            \"title\": \"Created\",\n            \"type\": \"boolean\"\n          },\n          \"has_auth\": {\n            \"const\": true,\n            \"description\": \"Always true: the provisioning wrote the keys.\",\n            \"title\": \"Has Auth\",\n            \"type\": \"boolean\"\n          },\n          \"issuer\": {\n            \"description\": \"The OIDC issuer the app's client validates against. One per deployment, shared by every app -- what separates them is the audience, which is the app's own id.\",\n            \"title\": \"Issuer\",\n            \"type\": \"string\"\n          },\n          \"kind\": {\n            \"description\": \"Always `managed` here, since a provision that answered anything else would have refused. Carried so the three sign-in routes report one field rather than three shapes a client has to tell apart.\",\n            \"enum\": [\n              \"none\",\n              \"managed\",\n              \"connected\"\n            ],\n            \"title\": \"Kind\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"has_auth\",\n          \"issuer\",\n          \"client_id\",\n          \"created\",\n          \"client_enabled\",\n          \"kind\"\n        ],\n        \"title\": \"AppAuthProvisionedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthUninvitedResponse\": {\n        \"description\": \"An address taken off the invite list, and the sessions it held.\\n\\nThe address is echoed folded, which is the form the list is keyed by.\",\n        \"properties\": {\n          \"email\": {\n            \"description\": \"The address taken off the list, echoed folded.\",\n            \"title\": \"Email\",\n            \"type\": \"string\"\n          },\n          \"revoked_sessions\": {\n            \"description\": \"How many sessions the withdrawn invite had admitted. Zero where the sweep failed, where the route could not work out whose sessions to end -- the address is resolved to an account after the delete commits -- and where there were none. `sweep_failed` covers the first two; `withdrawn` says whether there was a row to take.\",\n            \"title\": \"Revoked Sessions\",\n            \"type\": \"integer\"\n          },\n          \"sweep_failed\": {\n            \"description\": \"Whether ending that address's sessions is still owed, which is weaker than one still running: the flag is set by a failure to resolve the address at all, and it may hold no account or be admitted by the app whatever the list says. The row is deleted before any of it, so the withdrawal applied either way -- ``withdrawn`` says whether there was one to take.\",\n            \"title\": \"Sweep Failed\",\n            \"type\": \"boolean\"\n          },\n          \"withdrawn\": {\n            \"description\": \"Whether there was an invite to take. The route is idempotent, so withdrawing one that is not there is a success -- this is what separates that from a withdrawal that removed something, which the session count cannot: an address nobody invited can still be holding a session a peer's withdrawal left behind, and one that was on the list can be holding none.\",\n            \"title\": \"Withdrawn\",\n            \"type\": \"boolean\"\n          }\n        },\n        \"required\": [\n          \"email\",\n          \"revoked_sessions\",\n          \"sweep_failed\",\n          \"withdrawn\"\n        ],\n        \"title\": \"AppAuthUninvitedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthUserBlockedResponse\": {\n        \"description\": \"A block or unblock, in its two halves.\\n\\n``revoked_sessions`` counts what the sweep ended; ``sweep_failed`` is what\\nsays whether it ran. A sweep that failed reports zero and sets the flag,\\nrather than a null the flag beside it already says more about.\",\n        \"properties\": {\n          \"blocked\": {\n            \"description\": \"Where they stand now. On a 2xx this is what was asked for: an unblock that left them blocked -- because the sweep failed, or because a newer block stands -- is refused rather than answered here.\",\n            \"title\": \"Blocked\",\n            \"type\": \"boolean\"\n          },\n          \"blocked_at\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"When the block was made; null once it is lifted.\",\n            \"title\": \"Blocked At\"\n          },\n          \"revoked_sessions\": {\n            \"description\": \"How many live sessions were ended. Zero where the sweep failed as well as where there were none to end -- `sweep_failed` is what tells those apart, and it is the field to read.\",\n            \"title\": \"Revoked Sessions\",\n            \"type\": \"integer\"\n          },\n          \"sweep_failed\": {\n            \"description\": \"Whether ending this person's live sessions is still owed. Only a **block** can answer true here: it is written before the sweep, so it applied and how many sessions outlive it is unknown -- the sweep is one bulk call, so a person who was holding none reports this too. An **unblock** lifts the flag after, so a failed sweep deliberately leaves them blocked and changes nothing -- which is a 503 rather than a success, since there is no sense in which the request applied.\",\n            \"title\": \"Sweep Failed\",\n            \"type\": \"boolean\"\n          },\n          \"user_id\": {\n            \"description\": \"The subject the block is about.\",\n            \"title\": \"User Id\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"user_id\",\n          \"blocked\",\n          \"blocked_at\",\n          \"revoked_sessions\",\n          \"sweep_failed\"\n        ],\n        \"title\": \"AppAuthUserBlockedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthUserListResponse\": {\n        \"description\": \"A page of an app's users, and how many people there are in all.\\n\\n``search`` is echoed stripped, which is the term the page was filtered on.\",\n        \"properties\": {\n          \"limit\": {\n            \"description\": \"How many rows this page holds at most.\",\n            \"title\": \"Limit\",\n            \"type\": \"integer\"\n          },\n          \"offset\": {\n            \"description\": \"Where it started.\",\n            \"title\": \"Offset\",\n            \"type\": \"integer\"\n          },\n          \"search\": {\n            \"description\": \"The term the page was filtered on, echoed stripped -- which is the form it was applied in.\",\n            \"title\": \"Search\",\n            \"type\": \"string\"\n          },\n          \"total\": {\n            \"description\": \"How many match in all, so a client can page without walking to the end.\",\n            \"title\": \"Total\",\n            \"type\": \"integer\"\n          },\n          \"users\": {\n            \"description\": \"This page of the app's users.\",\n            \"items\": {\n              \"$ref\": \"#/components/schemas/AppAuthUserResponse\"\n            },\n            \"title\": \"Users\",\n            \"type\": \"array\"\n          }\n        },\n        \"required\": [\n          \"users\",\n          \"total\",\n          \"limit\",\n          \"offset\",\n          \"search\"\n        ],\n        \"title\": \"AppAuthUserListResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthUserResponse\": {\n        \"description\": \"One person an app has signed in.\\n\\nEach timestamp is named for the fact it holds: an agreement is not a\\nsign-in, and neither is a token refresh. ``last_active_at`` is null once\\nevery grant is gone rather than filled in from the consent beside it.\",\n        \"properties\": {\n          \"blocked\": {\n            \"description\": \"Whether the app refuses them a new sign-in. It does not end a session already running -- revoking their grants is what does that.\",\n            \"title\": \"Blocked\",\n            \"type\": \"boolean\"\n          },\n          \"blocked_at\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"When the app blocked them; null for somebody it has not.\",\n            \"title\": \"Blocked At\"\n          },\n          \"consented_at\": {\n            \"description\": \"Their last agreement. A sign-in that asked for nothing new leaves it alone, so it is when they last chose rather than when they were last here.\",\n            \"format\": \"date-time\",\n            \"title\": \"Consented At\",\n            \"type\": \"string\"\n          },\n          \"email\": {\n            \"description\": \"Withheld where the scope was: an app granted neither sees an opaque subject, so its owner is shown the same.\",\n            \"title\": \"Email\",\n            \"type\": \"string\"\n          },\n          \"first_consented_at\": {\n            \"description\": \"When they first agreed to sign in here, which is what created the row. Not a first sign-in: the code that consent minted can go unredeemed. It is the one instant that never moves, which is what the export pages on.\",\n            \"format\": \"date-time\",\n            \"title\": \"First Consented At\",\n            \"type\": \"string\"\n          },\n          \"last_active_at\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Their newest grant, which is as often a token renewal as a login -- deliberately not called a sign-in, since the row that *was* one goes with the prune. Null once every grant is gone rather than filled in from the consent beside it.\",\n            \"title\": \"Last Active At\"\n          },\n          \"name\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Withheld the same way as the address where the app was granted no profile scope.\",\n            \"title\": \"Name\"\n          },\n          \"user_id\": {\n            \"description\": \"The subject the app knows this person by: their platform account id, which is what the app's own code receives as `sub`.\",\n            \"title\": \"User Id\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"user_id\",\n          \"email\",\n          \"name\",\n          \"first_consented_at\",\n          \"last_active_at\",\n          \"consented_at\",\n          \"blocked_at\",\n          \"blocked\"\n        ],\n        \"title\": \"AppAuthUserResponse\",\n        \"type\": \"object\"\n      },\n      \"AppDatabaseAbsentResponse\": {\n        \"description\": \"An app with no managed database.\",\n        \"properties\": {\n          \"has_database\": {\n            \"const\": false,\n            \"description\": \"Always false on this body; the provisioned answer is the other member of the union.\",\n            \"title\": \"Has Database\",\n            \"type\": \"boolean\"\n          }\n        },\n        \"required\": [\n          \"has_database\"\n        ],\n        \"title\": \"AppDatabaseAbsentResponse\",\n        \"type\": \"object\"\n      },\n      \"AppDatabaseProvisionedResponse\": {\n        \"description\": \"A provisioning. ``created`` is false where one was already there.\",\n        \"properties\": {\n          \"created\": {\n            \"description\": \"Whether this call provisioned the database; false where one was already there and this answered with it.\",\n            \"title\": \"Created\",\n            \"type\": \"boolean\"\n          },\n          \"created_at\": {\n            \"description\": \"When it was provisioned.\",\n            \"title\": \"Created At\",\n            \"type\": \"string\"\n          },\n          \"database\": {\n            \"description\": \"The database name to connect to.\",\n            \"title\": \"Database\",\n            \"type\": \"string\"\n          },\n          \"has_database\": {\n            \"const\": true,\n            \"description\": \"Always true on this body; the no-database answer is the other member of the union, which carries it false.\",\n            \"title\": \"Has Database\",\n            \"type\": \"boolean\"\n          },\n          \"has_dev_branch\": {\n            \"description\": \"Whether a dev branch stands beside production, which is what a reset wipes. Without one a reset is refused unless the caller opts in by name, since the fallback would drop the deployed database.\",\n            \"title\": \"Has Dev Branch\",\n            \"type\": \"boolean\"\n          },\n          \"masked_connection_string\": {\n            \"description\": \"The connection string with its password removed. The real one is written into the app's own environment and is not served here.\",\n            \"title\": \"Masked Connection String\",\n            \"type\": \"string\"\n          },\n          \"project_id\": {\n            \"description\": \"The managed database project's id at the provider. Not the app id, which is only what the project is named after -- address the provider with this one.\",\n            \"title\": \"Project Id\",\n            \"type\": \"string\"\n          },\n          \"region\": {\n            \"description\": \"Where the database is provisioned.\",\n            \"title\": \"Region\",\n            \"type\": \"string\"\n          },\n          \"role\": {\n            \"description\": \"The role the connection string authenticates as.\",\n            \"title\": \"Role\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"has_database\",\n          \"project_id\",\n          \"region\",\n          \"created_at\",\n          \"database\",\n          \"role\",\n          \"masked_connection_string\",\n          \"has_dev_branch\",\n          \"created\"\n        ],\n        \"title\": \"AppDatabaseProvisionedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppDatabaseResponse\": {\n        \"description\": \"An app's managed database, with the connection string masked.\\n\\n``has_dev_branch`` is what a reset would wipe: without a dev branch,\\n``POST /database/reset`` drops the deployed database instead.\",\n        \"properties\": {\n          \"created_at\": {\n            \"description\": \"When it was provisioned.\",\n            \"title\": \"Created At\",\n            \"type\": \"string\"\n          },\n          \"database\": {\n            \"description\": \"The database name to connect to.\",\n            \"title\": \"Database\",\n            \"type\": \"string\"\n          },\n          \"has_database\": {\n            \"const\": true,\n            \"description\": \"Always true on this body; the no-database answer is the other member of the union, which carries it false.\",\n            \"title\": \"Has Database\",\n            \"type\": \"boolean\"\n          },\n          \"has_dev_branch\": {\n            \"description\": \"Whether a dev branch stands beside production, which is what a reset wipes. Without one a reset is refused unless the caller opts in by name, since the fallback would drop the deployed database.\",\n            \"title\": \"Has Dev Branch\",\n            \"type\": \"boolean\"\n          },\n          \"masked_connection_string\": {\n            \"description\": \"The connection string with its password removed. The real one is written into the app's own environment and is not served here.\",\n            \"title\": \"Masked Connection String\",\n            \"type\": \"string\"\n          },\n          \"project_id\": {\n            \"description\": \"The managed database project's id at the provider. Not the app id, which is only what the project is named after -- address the provider with this one.\",\n            \"title\": \"Project Id\",\n            \"type\": \"string\"\n          },\n          \"region\": {\n            \"description\": \"Where the database is provisioned.\",\n            \"title\": \"Region\",\n            \"type\": \"string\"\n          },\n          \"role\": {\n            \"description\": \"The role the connection string authenticates as.\",\n            \"title\": \"Role\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"has_database\",\n          \"project_id\",\n          \"region\",\n          \"created_at\",\n          \"database\",\n          \"role\",\n          \"masked_connection_string\",\n          \"has_dev_branch\"\n        ],\n        \"title\": \"AppDatabaseResponse\",\n        \"type\": \"object\"\n      },\n      \"AppFullDeployParams\": {\n        \"description\": \"Params for flipping only an app's full-deploy hosting mode.\",\n        \"properties\": {\n          \"full_deploy\": {\n            \"description\": \"Whether to bundle the frontend into the provider container and serve it beside the backend. GCP-only and Enterprise-only: true on an app hosted anywhere else is refused rather than ignored. Flipping a live app stops it, so the next redeploy comes up in the new mode.\",\n            \"title\": \"Full Deploy\",\n            \"type\": \"boolean\"\n          }\n        },\n        \"required\": [\n          \"full_deploy\"\n        ],\n        \"title\": \"AppFullDeployParams\",\n        \"type\": \"object\"\n      },\n      \"AppFullDeployResponse\": {\n        \"description\": \"An app's hosting mode after a flip.\\n\\nFlipping a live app stops it first, and ``stop_confirmed`` reports whether\\nthat whole teardown settled -- which is weaker than a confirmed destroy.\\nTrue where nothing was live.\",\n        \"properties\": {\n          \"full_deploy\": {\n            \"description\": \"The h\n\n<!-- [TRUNCATED AT 50KB] -->","packages/reflex-components-code/README.md":"# reflex-components-code\n\nReflex code display components.\n","packages/reflex-components-core/README.md":"# reflex-components-core\n\nUI components for Reflex.\n","packages/reflex-components-dataeditor/README.md":"# reflex-components-dataeditor\n\nReflex dataeditor components.\n","packages/reflex-components-gridjs/README.md":"# reflex-components-gridjs\n\nReflex gridjs components.\n","packages/reflex-components-internal/README.md":"# reflex-components-internal\n\nReflex internal components.\n","packages/reflex-components-lucide/README.md":"# reflex-components-lucide\n\nReflex lucide components.\n","packages/reflex-components-markdown/README.md":"# reflex-components-markdown\n\nReflex markdown components.\n","packages/reflex-components-moment/README.md":"# reflex-components-moment\n\nReflex moment components.\n","packages/reflex-components-plotly/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-components-plotly%2FREADME.md -->","packages/reflex-components-radix/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-components-radix%2FREADME.md -->","packages/reflex-components-react-player/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-components-react-player%2FREADME.md -->","packages/reflex-components-recharts/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-components-recharts%2FREADME.md -->","packages/reflex-components-sonner/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-components-sonner%2FREADME.md -->","packages/reflex-docgen/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-docgen%2FREADME.md -->","packages/reflex-hosting-cli/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-hosting-cli%2FREADME.md -->","packages/reflex-otel/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-otel%2FREADME.md -->","packages/reflex-release/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-release%2FREADME.md -->","packages/reflex-site-shared/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-site-shared%2FREADME.md -->","packages/reflex-workflow/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-workflow%2FREADME.md -->","packages/reflex-workflow/benchmarks/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-workflow%2Fbenchmarks%2FREADME.md -->","packages/reflex-workflow/examples/README.md":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-workflow%2Fexamples%2FREADME.md -->"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Coding Agent Guidelines\n\nReflex: Python web **framework** compiling to React. Monorepo using uv workspace — main package in `reflex/`, sub-packages in `packages/`, docs site in `docs/`.\n\n## Workflow\n\n1. **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.\n2. **Bugfixes:** write a regression test that fails before writing the fix.\n3. **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.\n\n## Commands\n\nUse `uv` for everything — never bare `python` or `python3`.\n\n```\nuv sync                                                          # install deps\nuv run pytest tests/units --cov --no-cov-on-fail --cov-report=   # unit tests (>=72% coverage)\nuv run pytest tests/integration                                  # integration tests (slow)\nuv run ruff check .                                              # lint\nuv run ruff format .                                             # format\nuv run pyright reflex tests                                      # type check\nuv run python scripts/check_min_deps.py                          # validate each package's declared minimum dep versions (pyright in isolated min-version envs; workspace siblings resolve from locally built wheels, all other deps from PyPI). CI passes --wheelhouse instead, reusing the build jobs' artifacts\nuv run python scripts/check_min_deps.py --check-dev-pins [pkg]    # fail if pkg (default: all) declares an unpublishable *.dev dependency pin (the publish workflow runs the same gate via `reflex-release check-dev-pins`)\nuv run reflex-release sync                                       # regenerate the release workflows after editing [tool.reflex-release] or the reflex-release templates\nuv run python scripts/make_pyi.py                                # regenerate .pyi stubs\nuv run pre-commit run --all-files                                # all pre-commit hooks\n```\n\n## Layout\n\n```\nreflex/                 # main framework package (app, state, compiler, components, utils, istate)\npackages/               # workspace sub-packages (reflex-base, reflex-components-*, reflex-docgen, reflex-components-internal)\ntests/units/            # unit tests, mirrors source tree\ntests/integration/      # Selenium integration tests (run in dev+prod modes)\n  tests_playwright/     # Playwright integration tests (preferred for new tests)\ntests/benchmarks/       # performance benchmarks\ndocs/                   # documentation site (separate workspace member)\n```\n\n## Code style\n\n- Concise, robust code. Reflex is a framework used in many ways — handle edge cases without unnecessary complexity.\n- 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.\n- Don't add expensive workarounds (e.g. `isinstance` checks) to paper over type-level problems — fix the root cause instead.\n- Don't repeat validation or be over-defensive; trust data that was already validated upstream.\n- Think in CPU cycles: avoid unnecessary data copies, redundant allocations, and gratuitous indirection.\n- Extract duplicated code into parameterized helpers.\n- No block comments (`# --- Section ---`, `# ============`). Plain inline comments only.\n- Be cautious creating new public APIs — they must be documented and supported long-term.\n- Google-style docstrings on all functions: one-line summary, optional detail sentence(s), then Args/Returns (or Yields)/Raises.\n- Prefer imports at the top of the module in isort order. Only use inline imports when necessary to avoid circular dependencies.\n\n## Testing\n\n- Write comprehensive tests for new/changed features; extend existing test files where possible.\n- Test functions at module level, not wrapped in classes.\n- **Unit tests:** `tests/units/`, run with `uv run pytest tests/units`.\n  - 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`).\n- **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.\n\n### Integration test patterns\n\nApps as factory functions, run via `AppHarness`:\n\n```python\ndef SomeApp():\n    import reflex as rx\n\n    class State(rx.State):\n        value: str = \"\"\n\n    def index():\n        return rx.box(rx.text(State.value))\n\n    app = rx.App()\n    app.add_page(index)\n\n\n@pytest.fixture(scope=\"module\")\ndef some_app(tmp_path_factory) -> Generator[AppHarness, None, None]:\n    with AppHarness.create(\n        root=tmp_path_factory.mktemp(\"some_app\"), app_source=SomeApp\n    ) as harness:\n        yield harness\n```\n\nPlaywright tests use the `page` fixture and navigate to `harness.frontend_url`. Utilities in `tests/integration/utils.py` (polling, event ordering, storage).\n\n## .pyi stubs\n\nWhen 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.\n\n## CI workflows\n\nBranch rules require one check per workflow, listed in\n`.github/rulesets/main-required-checks.json`. Check names are matched literally —\nno wildcards — so two rules follow:\n\n- **A required workflow must not filter its `pull_request` trigger.** A workflow\n  a path filter skips never reports its checks, so a required check on it blocks\n  the merge forever. Filter in a `changes` job instead and gate the real jobs on\n  `if: needs.changes.outputs.run == 'true'` — a job skipped by `if:` reports as a\n  pass. `push` triggers may keep their filters; nothing gates a merge there. So\n  may a workflow that blocks no merge — absent from the ruleset and listed in\n  that test's `ADVISORY` — where the filter costs a run rather than a merge.\n- **Every merge-blocking workflow ends in a gate job** named `<workflow>-gate`,\n  which collapses it into one check name that matrix expansion cannot move. The\n  exception is a workflow with one job whose name cannot drift — `pre-commit`,\n  `changelog` — which the ruleset requires by that name (`DIRECTLY_REQUIRED` in\n  the test). A gate looks like:\n\n```yaml\n  unit-tests-gate:\n    needs: [changes, unit-tests, unit-tests-macos]  # every other job\n    if: always()  # not !cancelled(): a cancelled run would report a pass\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@... # v6.0.2\n        with:\n          persist-credentials: false\n      - uses: ./.github/actions/ci_gate\n        with:\n          needs: ${{ toJSON(needs) }}\n```\n\nAdding a job means adding it to the gate's `needs`; adding a workflow means\nadding its gate to the ruleset. `tests/units/test_workflow_gates.py` fails when\neither drifts. Every matrix leg blocks through its gate, pre-release Python\nversions included, so leave `continue-on-error` off a gated job. A workflow\ndisabled in the repository's Actions settings never reports, which no test can\nsee: disabling one means moving it to `ADVISORY` and out of the ruleset, or every\nmerge waits on it.\n\n## Changelog fragments\n\nUser-facing changes need a news fragment in the `news/` directory of each\npackage they touch (the repo root's `news/` for `reflex`), named\n`+<slug>.<type>.md`. Putting the PR number in the name (`<PR number>.<type>.md`)\nis optional: the release process renames an orphan fragment when it can identify\nthe PR that added it, so its entry links to that PR. Don't push a commit just to\nrename one. Types: `breaking`, `deprecation`, `feature`, `bugfix`,\n`performance`, `docs`, `misc`.\n\nWrite for external downstream users, not for reviewers. Every entry links to\nits PR, so motivation, narrative, and implementation details belong in the PR\nand the commit message — a reader who wants them will follow the link. Keep the\nfragment to a sentence or two saying what changed and what it means for a user:\n\n> Reduce published wheel and sdist size by removing misplaced generated artifacts.\n\nBrevity is about the narrative, not the substance: whatever is genuinely useful\ndownstream belongs in the fragment. A brief usage example for a new feature, or\nthe before/after of converting deprecated usage to the supported style, earns\nits place. Once it runs past a few sentences and a small code block, it is\ndocumentation — write it under `docs/` and let the fragment link there.\n\nCI requires a fragment for every package whose source the PR touches; the\n`skip-changelog` label waives it for changes that are genuinely not user-facing.\n\n## Sibling dependency floors\n\nWhen a package needs an unreleased change in a workspace sibling, raise its\nfloor on that sibling to the `.dev0` of the sibling's next version. Every\npackage derives its version with `bump = true`, so each commit after its newest\ntag builds as a dev release of that next version:\n\n- after `reflex-base-v0.9.12`: `reflex-base >= 0.9.13.dev0`\n- after `reflex-components-core-v0.9.10.post1`: `reflex-components-core >= 0.9.10.post2.dev0`\n\nSuch a floor excludes every release up to that tag and is met by every later\ncommit, so check-min-deps passes. A post release of the sibling cut after the\nfloor was written leaves main building below it; re-floor at that post release.\nReleasing the dependent lifts it to the first\npublished version that satisfies it (see `packages/reflex-release/README.md`,\n\"Dependency pins across a release\"). A floor the workspace can't meet fails\ncheck-min-deps with \"builds as ... here\".\n\n## Breaking changes and deprecation\n\nReflex has downstream users — don't break them. Provide a fallback path during deprecation.\n\n**Runtime warning** via `console.deprecate()`:\n```python\nfrom reflex_base.utils import console\n\nconsole.deprecate(\n    feature_name=\"OldFeature\",\n    reason=\"Use NewFeature instead.\",\n    deprecation_version=\"<next dot version of latest git tag>\",\n    removal_version=\"1.0\",\n)\n```\nSet `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.\n\n**Type-level deprecation** for deprecated methods/overloads using `typing_extensions.deprecated`, always inside a `TYPE_CHECKING` guard to avoid double warnings:\n```python\nfrom __future__ import annotations\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from typing_extensions import deprecated\n\n    @deprecated(\"Use new_method() instead\")\n    def old_method(self) -> str: ...\n```\n\n## Checklist\n\nBefore submitting:\n1. Tests pass with adequate coverage\n2. `uv run ruff check .` and `uv run ruff format .` clean\n3. `uv run pyright reflex tests` passes\n4. `pyi_hashes.json` updated if components changed\n5. Documentation updated if user-facing behavior changed\n6. News fragment added for user-facing changes\n7. Deprecation warnings added if breaking changes introduced\n","isInternal":false,"tokens":2584,"sizeBytes":11405},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"AGENTS.md","isInternal":false,"tokens":3,"sizeBytes":9},{"name":"agent-brief.md","path":".claude/skills/prerelease-test/references/agent-brief.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/.claude/skills/prerelease-test/references/agent-brief.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# The agent brief\n\nCopy this into the campaign scratchpad (e.g. `$SB/AGENT_BRIEF.md`), fill the `<...>` placeholders,\nand tell every test agent to read it first. It carries the rules that keep results trustworthy and\nthe environment traps that otherwise get rediscovered — expensively — by each agent in turn.\n\nKeep it in a file rather than pasting it into each prompt: agents re-read it when they get\nconfused, and updating one file updates the whole fleet.\n\n---\n\n## BRIEF TEMPLATE (copy from here)\n\nYou are one of several agents independently exercising the reflex `<VERSION>` pre-release\n(published `<DATE>`) as a real-world user of the framework. Your job: build small sample apps and\nrepro scripts for your assigned feature cluster, run them END-TO-END (real server, real Chromium),\nand hunt for anomalies. You REPORT issues; you never fix framework code.\n\n### HARD RULES\n\n1. **NEVER install reflex (or any workspace package) from the local checkout at `<REPO>`.** No\n   `uv sync`, no `uv run`, no `pip install -e`, no `uv pip install .` anywhere under it.\n   Everything installs from PyPI. We are testing what users receive, not what the tree contains.\n2. **Never run python with the checkout as your working directory.** `<REPO>/reflex/` shadows the\n   installed package, so `import reflex` silently picks up unreleased source and your results\n   become fiction. Run scripts from a neutral directory and start each repro with an assertion\n   naming the venv whose python is running it — the shared one below, or your own:\n   ```python\n   import reflex\n\n   assert \"<VENV_PATH>\" in reflex.__file__, reflex.__file__\n   ```\n   A guard that names some other venv fails on every run and gets deleted, which leaves you with\n   no guard at all.\n3. Reading the checkout is fine and encouraged — release source is on branch `<PRERELEASE_BRANCH>`.\n   For PR context load the GitHub MCP tools via ToolSearch (`select:mcp__github__pull_request_read`).\n4. Do NOT run any `git` write commands (add/commit/checkout/...) in the checkout. The orchestrator\n   commits artifacts.\n5. Do NOT fix bugs you find — record precise repro steps instead.\n6. Kill every server and browser you start before you finish (track PIDs; verify with `ps`). Other\n   agents share this machine — run at most ONE dev server at a time unless your cluster needs two.\n\n### Environment\n\n- Scratchpad root: `SB=<SCRATCHPAD>`\n- **Prebuilt shared venv (READ-ONLY — never install into it):** `$SB/envs/<SHARED_VENV>` has\n  `reflex==<VERSION>` and the alpha sub-packages. Use `$SB/envs/<SHARED_VENV>/bin/reflex` directly.\n- Need other deps or versions? Make your OWN venv:\n  ```\n  uv venv $SB/envs/<yours> --python 3.11\n  uv pip install --python $SB/envs/<yours>/bin/python --prerelease=allow 'reflex==<VERSION>' <extras>\n  ```\n  Always pass `--prerelease=allow` for alphas; PyPI is the default index — never point it at the\n  checkout. Python 3.12/3.13/3.14 are available via `uv venv --python 3.14` etc.\n- **Playwright driver venv:** `$SB/envs/driver/bin/python` (playwright, httpx, websockets).\n  Chromium: `/opt/pw-browsers/chromium` — launch with\n  `p.chromium.launch(executable_path=\"/opt/pw-browsers/chromium\")`.\n  A ready-made driver with console/network capture is at\n  `.claude/skills/prerelease-test/scripts/drive_app.py` in the checkout (read-only use is fine).\n- **Local HTTP needs proxy bypass on the CLIENT side only:** prefix curl/Playwright commands with\n  `NO_PROXY=localhost,127.0.0.1 no_proxy=localhost,127.0.0.1` (curl: `--noproxy '*'`).\n  Do NOT export those variables into the reflex server's environment — it breaks bun's package\n  installs through the proxy, which looks like a framework bug and is not.\n- Set `REFLEX_TELEMETRY_ENABLED=false` for every reflex command.\n- Node and bun are preinstalled. Enterprise apps need `CI=true` to bypass the dev login gate.\n- App working dirs: `$SB/apps/<cluster>/...`. Run servers on YOUR ASSIGNED PORTS:\n  `reflex run --frontend-port <FP> --backend-port <BP>`. The first run does a bun install (1–2 min);\n  poll the frontend URL until it returns 200 for up to ~6 minutes before concluding failure.\n- `--loglevel debug` gives verbose server logs; redirect to a file and actually read it.\n\n### What \"testing\" means here\n\n- Real-world exploration, not coverage filling. Combine the feature with State vars,\n  `rx._x.client_state`, `@rx.memo` wrapping, `rx.ComponentState`, `rx.foreach`/`rx.cond`, event\n  chains (`yield Other.handler()`), background tasks, multiple pages and navigation — whatever\n  plausibly interacts. The original PR already tested the happy path.\n- Drive the app in Chromium as a user would: click, type, navigate, upload, drag, use the keyboard.\n- On EVERY run capture and inspect: (a) the server log file, (b) browser console messages (errors\n  AND warnings), (c) failed requests / 4xx-5xx responses, (d) screenshots at key moments.\n- Baseline comparisons are what make findings actionable: if behavior looks wrong, check the\n  previous stable (`uv pip install 'reflex==<PREV_STABLE>'` in its own venv). Only-on-new is a\n  regression and high severity; both-versions is context worth noting, not a blocker.\n- Prod matters too: `reflex run --env prod` compiles and serves the built frontend. Test both modes\n  when your feature could differ (hydration, memoization, routing, prerender).\n\n### Known-benign noise — do not report these as findings\n\n- Browser console: the React Router \"💿 Hey developer\" HydrateFallback log, vite\n  `connecting.../connected` debug lines, the React DevTools download info line.\n- `reflex init` logging a few \"Failed to connect to https://registry.npmmirror.com\" lines before\n  falling back (this environment blocks that mirror). Do report it if the fallback itself fails.\n- Transient bun \"incorrect peer dependency\" warnings during a one-time upgrade migration, provided\n  the final lockfile is consistent.\n\nIf you see something surprising that is not on this list, investigate it — several real findings\nhave surfaced first as an unexplained warning.\n\n### Deliverables (mandatory)\n\n1. Copy reusable artifacts into the repo (plain `cp`/`rsync`, no git):\n   `DEST=<ARTIFACT_ROOT>/<cluster>/`\n   - the app source dirs, EXCLUDING `.web/`, `node_modules/`, `.states/`, `assets/external/`,\n     `*.db`, venvs\n   - your Playwright/repro scripts\n   - `NOTES.md`: what you tested, how to rerun it (exact commands), what you observed, including\n     benign quirks\n2. Return structured findings: every discrete check as a test entry (pass/fail/anomaly/skipped)\n   with enough repro detail that another agent can reproduce a failure from `NOTES.md` and your\n   scripts alone, without your conversation. An \"anomaly\" is anything surprising (console error,\n   warning, traceback, visual glitch, perf cliff) even when functionality works.\n\n### Timeboxing\n\nBe thorough but keep moving: if one sub-test resists debugging for ~10 minutes, record it as an\nanomaly with logs attached and continue. Finishing the whole cluster beats perfecting one test.\n","isInternal":false,"tokens":1742,"sizeBytes":7035},{"name":"clusters.md","path":".claude/skills/prerelease-test/references/clusters.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/.claude/skills/prerelease-test/references/clusters.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Cutting the changelog into clusters\n\nA cluster is one agent's assignment: a group of changelog entries that share a subsystem, so the\nagent can build one or two apps that exercise all of them together and notice how they interact.\n\n## How to cut them\n\nGroup by **where the change lives at runtime**, not by which PR shipped it. Entries that touch the\nsame subsystem belong together even when they came from unrelated PRs, because the interesting\nbugs are in their interaction — and one app can cover them all.\n\nAim for 8–12 clusters of 2–6 changelog entries each. A cluster that needs more than two apps is\ntoo big; one with a single trivial entry should be folded into a neighbour.\n\nEach cluster brief should carry:\n- the changelog lines verbatim (agents should not have to re-derive what shipped),\n- the PR numbers, so the agent can read intent,\n- concrete \"combine it with\" suggestions — this is what turns a checklist into exploration,\n- anything the entry implies but does not state (a perf claim to measure, a behavior that should\n  differ between dev and prod).\n\n## Standing coverage checklist\n\nMost Reflex releases touch some subset of these. Use it to check you have not left a shipped change\nunassigned, and as a source of interaction ideas.\n\n| Area | What to build | Interactions worth forcing |\n|---|---|---|\n| Routing / navigation | Multi-page app with dynamic (`[id]`), catchall (`[[...splat]]`) and static-sibling routes; slow `on_load` | Navigate away mid-`on_load`; two tabs on different dynamic values; browser back/forward; direct load vs client-side nav; prod mode |\n| State & event loop | Counter hammered by clicks while a background task writes | Background task + foreground handler racing; `yield`-streaming handlers; `async with self`; abrupt disconnect mid-stream |\n| Components / props | One page per changed component | Prop bound to a State var, to a `client_state` var, and inside `@rx.memo`; explicit `style=` merged with forwarded props |\n| Memoization | `@rx.memo` component with state-bound props and an event-handler prop, plus render counters | Memo in `rx.foreach`; memo wrapping `ComponentState`; two memos sharing a name in different modules; dev vs prod |\n| Typing / annotations | State vars using every annotation shape the entry mentions | Assign at runtime (not just compile); pass the handler *uncalled* to a trigger; run on the oldest and newest supported Python |\n| Uploads | `rx.upload` with buffered and streamed handlers | Hostile filenames (traversal, unicode, all-dots, spaces); raw multipart via httpx alongside browser uploads |\n| Logging / CLI | Run every CLI verb with and without the logging flags | Strict JSON-lines parsing of stdout; a user app that configures `logging` itself; missing optional sub-packages |\n| Config / plugins | App with the config knob set, unset, and set via env var | Deprecated form alongside the new form; plugin explicitly enabled vs implicit |\n| Build / prod / export | Multi-page app through `run --env prod`, `export`, `run --env preview` | Serve exported frontend statically with a backend-only server; inspect generated `.web/package.json`; custom component with a changed library |\n| Registration / multi-app | Two apps in one process; `AppHarness` twice | Sequential and simultaneous; check for registration leakage between them |\n| Optional dependencies | Bare install, each extra, and the upgrade path | Import the optional package's feature without the extra and judge the error message quality |\n| DevTools / perf | App with nested substates, custom components, client-only wrappers | Walk React fibers for `displayName`; record navigation main-thread cost; verify perf claims rather than trusting them |\n\n## Downstream and packaging clusters\n\nTwo clusters that are not feature-shaped but catch the highest-severity problems:\n\n- **Breaking-change surface.** For every entry under \"Breaking Changes\" (and every removal you spot\n  in the diff), ask what a downstream caller sees. Grep the published `reflex-enterprise` wheel and\n  the popular third-party packages (`reflex-local-auth`, `reflex-global-hotkey`) for the removed\n  names. A bare `AttributeError`/`ImportError` with no pointer to the replacement is a finding even\n  when the removal itself was intended.\n- **Packaging.** `.claude/skills/prerelease-test/scripts/audit_pyi.py`, plus a check that each package's declared dependency pins\n  match what the changelog says and that installing from the sdist works.\n","isInternal":false,"tokens":970,"sizeBytes":4475},{"name":"orchestration.md","path":".claude/skills/prerelease-test/references/orchestration.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/.claude/skills/prerelease-test/references/orchestration.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Orchestrating the fleet\n\n## Choosing the mechanism\n\nInvoking this skill is itself the opt-in for the Workflow tool, so a full campaign should use it —\nthe explore→verify pipeline is deterministic control flow over many agents, exactly what Workflow\nis for. For a quick check or a single cluster, plain `Agent` calls are simpler and cheaper.\n\nUse one workflow per phase rather than one giant script. Phase results change what you want to ask\nnext (a cluster that finds a breaking change reshapes the enterprise phase), and you stay in the\nloop between phases.\n\n## The explore → verify pipeline\n\nThe shape that matters: each cluster's findings go straight into verification without waiting for\nthe other clusters. Use `pipeline`, not a barrier — a slow cluster should not hold up verification\nof a fast one.\n\n```js\nexport const meta = {\n  name: 'prerelease-explore',\n  description: 'Exercise <version> feature clusters end-to-end, then adversarially verify findings',\n  phases: [{ title: 'Explore' }, { title: 'Verify' }],\n}\n\nconst SB = '<scratchpad>'\nconst DEST = '<artifact root>'\n\nconst FINDINGS_SCHEMA = {\n  type: 'object',\n  required: ['cluster', 'summary', 'tests', 'issues', 'artifacts_dir'],\n  properties: {\n    cluster: { type: 'string' },\n    summary: { type: 'string' },\n    tests: {\n      type: 'array',\n      items: {\n        type: 'object',\n        required: ['name', 'status', 'details'],\n        properties: {\n          name: { type: 'string' },\n          status: { type: 'string', enum: ['pass', 'fail', 'anomaly', 'skipped'] },\n          details: { type: 'string' },\n          repro: { type: 'string' },\n        },\n      },\n    },\n    issues: {\n      type: 'array',\n      items: {\n        type: 'object',\n        required: ['title', 'severity', 'repro'],\n        properties: {\n          title: { type: 'string' },\n          severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low'] },\n          repro: { type: 'string' },\n          evidence: { type: 'string' },\n          regression: { type: 'boolean', description: 'true if the previous stable behaves correctly' },\n        },\n      },\n    },\n    artifacts_dir: { type: 'string' },\n  },\n}\n\nconst VERDICT_SCHEMA = {\n  type: 'object',\n  required: ['confirmed', 'notes'],\n  properties: {\n    confirmed: { type: 'boolean' },\n    notes: { type: 'string' },\n    root_cause_guess: { type: 'string' },\n  },\n}\n\nphase('Explore')\nconst results = await pipeline(\n  CLUSTERS,\n  (c, _item, i) => agent(brief(c, i), { label: `explore:${c.key}`, phase: 'Explore', schema: FINDINGS_SCHEMA }),\n  async (res, c, i) => {\n    if (!res) return { cluster: c.key, agent_died: true }\n    // Cap the fan-out per cluster. Issues past the cap are absent from verified_issues but\n    // still present in res.issues, which is how the report tells them from verified ones.\n    const issues = (res.issues || []).slice(0, 4)\n    if (!issues.length) return res\n    const verdicts = await parallel(\n      issues.map((iss, j) => () =>\n        agent(verifyBrief(c, iss, j), { label: `verify:${c.key}:${j}`, phase: 'Verify', schema: VERDICT_SCHEMA })\n          // A dead verifier resolves falsy. Give it its own marker: `verdict: null` would\n          // read as a verdict that cleared the issue, and dropping the entry would leave a\n          // hole indistinguishable from an issue the cap never sent to a verifier.\n          .then((v) => (v ? { issue: iss, verdict: v } : { issue: iss, verifier_died: true })),\n      ),\n    )\n    return { ...res, verified_issues: verdicts }\n  },\n)\n// Dead explorers stay in as `agent_died` markers rather than being filtered out: a cluster\n// that produced nothing is a hole in the campaign, and silently dropping it is how a hole\n// gets mistaken for a clean result. Same for `verifier_died` above. Every marker is work\n// the campaign did not do, so the report must account for each one rather than skip it.\nreturn results.filter(Boolean)\n```\n\nThe verifier's prompt is what makes this work. It must:\n- reproduce **from the written repro alone**, in its own working directory, not by reading the\n  reporter's conversation — that is simultaneously a test of the repro's quality,\n- be told to actively **refute**: is this an environment quirk, an API misuse, pre-existing on the\n  previous stable, or a genuine defect?\n- set `confirmed: true` only for a genuine defect a fix agent should act on,\n- append a `## VERIFICATION` section to the cluster's `NOTES.md` so the record travels with the\n  artifacts.\n\n## Port map\n\nGive every agent a disjoint range and tell it to always pass `--frontend-port/--backend-port`\nexplicitly. Never let anything use the defaults (3000/8000) — that is how two agents collide and\nproduce confusing, unreproducible results.\n\n| Stage | Frontend | Backend |\n|---|---|---|\n| Explore agent *i* | `3100 + 40i` … +19 | `8100 + 40i` … +19 |\n| Verify agent *i.j* | `3600 + 40i + 4j` … +3 | `8600 + 40i + 4j` … +3 |\n| Orchestrator smoke | 3050–3059 | 8050–8059 |\n\n## Prompt scaffolding for each agent\n\nEvery cluster prompt should open with the same preamble, then the cluster-specific brief:\n\n```\nFIRST read <SB>/AGENT_BRIEF.md and follow every rule in it (isolated PyPI-only installs — never\ninstall from the checkout; end-to-end browser testing; artifact + NOTES.md deliverables; kill your\nprocesses).\nYour cluster key: \"<key>\". Working dir: <SB>/apps/<key>/. Artifact destination: <DEST>/<key>/.\nYour RESERVED ports: frontend <FP_START>-<FP_END>, backend <BP_START>-<BP_END> — always pass them\nexplicitly, and never bind outside them.\n<cluster brief: changelog lines verbatim, PR numbers, combine-with suggestions>\nAlso in scope: anything adjacent you notice (log warnings, console anomalies, network errors,\nvisual glitches). Record benign-but-surprising observations in NOTES.md and as 'anomaly' entries.\n```\n\nFill the port ends from the table above, not from a fixed span: an explore agent's range is 20\nports wide and a verify agent's is 4. A verifier told it owns 20 would reach into the next\nverifier's range, which is the collision the map exists to prevent.\n\n## Running it\n\n- Two agents at a time is right for a 4-CPU box; the workflow's own concurrency cap handles the\n  rest of the queue.\n- Between phases, read the results before launching the next one.\n- Schedule a check-in (`send_later`, ~45 min) during long runs so a wedged agent or a leaked dev\n  server gets noticed. Check `ps` for stray `reflex run` processes and commit finished clusters.\n- When the workflow completes, its full structured result is in the task output file; parse it for\n  the report rather than re-reading transcripts.\n","isInternal":false,"tokens":1671,"sizeBytes":6639},{"name":"reporting.md","path":".claude/skills/prerelease-test/references/reporting.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/.claude/skills/prerelease-test/references/reporting.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Reporting\n\n## FINDINGS.md\n\nThe audience is a maintainer deciding what blocks the release, and fix agents who will get handed\none finding and nothing else. Write for both: a summary that supports a go/no-go call, and findings\nself-contained enough to act on in isolation.\n\n```markdown\n# Findings — reflex <version> pre-release testing (<date>)\n\n<One paragraph on method: PyPI-only isolated venvs, end-to-end browser runs, previous-stable\nbaselines, independent adversarial verification of every claimed issue. Agent count.>\n\n## Versions under test\n<Every package and version, noting which are new in this train and that each is published.>\n<Environment: OS, CPU/RAM, node/bun, python versions, browser.>\n\n## Executive summary\n<What works — name the headline changelog items verified.>\n<What blocks — the short list, with severity.>\n<Severity histogram, and the count of refuted claims.>\n\nIndex:\n- FINDING-001: <title> (SEVERITY)\n- ...\n\n## FINDING-00N: <title> (SEVERITY)\n\n- Cluster: `<cluster>` | Regression vs <prev stable>: yes/no | Verifier: CONFIRMED\n- Repro: <exact commands/steps, self-contained>\n- Evidence: <log excerpt, console error, screenshot path>\n- Root cause (verifier analysis): <file:line and mechanism, when known>\n- Verification notes: <what the independent reproducer found>\n\n## Refuted / reclassified claims\n- **<title>** (`<cluster>`): <why it is not an actionable defect for this release>\n\n## Cluster summaries\n### `<cluster>` (pass:N, anomaly:N, fail:N)\n<2-4 sentences: what was built, what was verified, what was found.>\n```\n\nTwo things carry disproportionate weight and are easy to skip:\n\n- **The refuted list.** It shows the findings were filtered, which is why a maintainer can trust the\n  ones that remain. Never quietly drop a refuted claim.\n- **Regression status on every finding.** \"Broken in both versions\" and \"newly broken\" lead to\n  opposite decisions, and the reader cannot recover that from the description.\n\n## RELEASE_PLAN.md\n\n```markdown\n# Release plan — what blocks <version> vs what gets filed\n\n## Already in flight\n| PR | Covers | Gap check |\n<For each open PR, which findings it addresses and — importantly — what it does NOT cover.>\n\n## Fix before release\n### Security\n### Confirmed regressions\n### High impact and/or trivially small\n<Each item: finding ref, one-line rationale tied to the rubric, and the shape of the fix.>\n\n## File as issues, fix after release\n### <this repo>\n### <downstream repo>\n\n## Decisions needed from a maintainer\n<Behavior changes that are either bugs or missing changelog entries — their call, not yours.>\n\n## Suggested sequencing\n<Order of PRs, noting which can land in parallel and which touch the same files.>\n```\n\nThe rubric (confirmed regression / security / significant-impact-or-trivial) is in `SKILL.md`.\nApply it visibly: each entry should say which arm of the rubric put it there, so the maintainer can\ndisagree with a specific judgment rather than the whole list.\n\n## Filing issues\n\nFor post-release items: search for duplicates first (2–3 keyword variants, open *and* closed), then\nfile with a self-contained repro, observed vs expected, environment, a note that it came from\n`<version>` pre-release testing, and a pointer to the artifacts branch and cluster directory.\nMirror `.github/ISSUE_TEMPLATE/bug_report.md` where it fits.\n\n## If the user asks for the fixes afterwards\n\nThat is a separate engagement. What worked well:\n\n- **One PR per finding**, branched from current `main`, in its own git worktree so parallel fix\n  agents never collide.\n- **Regression test first**: write it, show it failing against unfixed `main`, then fix, then show\n  it passing. Report both states in the PR body — a reviewer should not have to take it on faith.\n- **News fragment** under the right package's `news/` directory. The changelog CI gate checks per\n  package: a fix touching `packages/reflex-base/` needs a fragment in\n  `packages/reflex-base/news/`, and a root-only fragment will fail the gate.\n- **Adversarial review of each PR** before handing it over: an independent agent re-runs the\n  regression test against unfixed source to confirm it actually pins the bug, and checks repo\n  conventions. This catches PRs whose test passes either way.\n- PR body: cite the FINDING number and that it came from pre-release testing, describe the defect\n  mechanism, the fix, and the test plan including the failing-before evidence.\n- Watch CI after opening (`subscribe_pr_activity`) and drive each PR to green.\n","isInternal":false,"tokens":1061,"sizeBytes":4500},{"name":"SKILL.md","path":".claude/skills/prerelease-test/SKILL.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/.claude/skills/prerelease-test/SKILL.md","title":"prerelease-test","category":"anthropic-skill","format":"markdown","content":"---\nname: prerelease-test\ndescription: Run the independent pre-release QA campaign for a Reflex release train. Discovers what shipped by reading every CHANGELOG.md on the pre-release branch, checks each package actually published to PyPI, then exercises the new features end-to-end in real apps driven by a real browser using ONLY published packages, upgrade-tests reflex-examples apps from the previous stable, regression-tests reflex-enterprise demos, audits wheel/sdist packaging, and produces a triaged FINDINGS.md plus a fix-before-release plan. Use this whenever a Reflex release is being prepared or checked — the user mentions a pre-release, an alpha/beta/rc, an `r/pre-*` branch, \"about to release\", release QA, validating a release candidate, or re-verifying that release-blocking fixes landed in a newer alpha. Also use it for the narrower slices on their own: smoke-testing published packages, upgrade/regression testing example apps against a new version, or auditing that packages ship their `.pyi` stubs in both wheel and sdist.\n---\n\n# Reflex pre-release testing\n\nThis skill runs the QA campaign that stands between a pre-release and a release: independent,\nadversarial, end-to-end exercise of what actually got published, from the perspective of a user\nwho runs `pip install reflex` and opens a browser.\n\nIts value comes from three habits, not from breadth of assertions:\n\n1. **Only published packages.** Everything installs from PyPI into throwaway venvs. The checkout\n   has unreleased code, different metadata, and a different dependency graph — testing it tells\n   you nothing about what users will get, and a package that failed to publish is itself a\n   release blocker you would otherwise miss.\n2. **Baseline against the previous stable.** A defect that also reproduces on the last release is\n   a bug; one that only reproduces on the new version is a regression and usually a blocker.\n   Without the baseline run you cannot tell them apart, and the triage that follows is guesswork.\n3. **Adversarially verify before reporting.** Have a second agent reproduce each claimed issue\n   from the written repro alone and actively try to refute it. In practice this refutes or\n   reclassifies a meaningful share of findings — and it is what makes the report trustworthy\n   enough for maintainers to act on directly.\n\n## Deliverables\n\nProduce these under `prerelease-testing/<date>-<version>/` in the repo and commit them to a work\nbranch as you go (never to `main`):\n\n- `FINDINGS.md` — executive summary, numbered findings with repro + evidence + regression status,\n  refuted claims, and per-cluster summaries. Templates: `references/reporting.md`.\n- `RELEASE_PLAN.md` — triage into fix-before-release vs file-as-issue. Rubric below.\n- One directory per test cluster containing the sample app sources (no `.web/`, `node_modules/`,\n  venvs), the driver scripts, `NOTES.md` with exact rerun commands, logs and screenshots.\n- `README.md` — what each cluster covers and how to reuse it for the next release.\n\nFindings must be reproducible by a stranger from `NOTES.md` alone. That is the bar: a fix agent\ngets handed the finding and nothing else.\n\n## Phases\n\nWork these in order. Phases 2–5 can overlap; 0 and 1 gate everything.\n\n### Phase 0 — Scope discovery\n\nFind the pre-release branch (`git ls-remote --heads origin 'r/pre-*'`, or the user names it), then\nread **every** `CHANGELOG.md` on it: the root one plus `packages/*/CHANGELOG.md`. The top entry of\neach is what this train ships.\n\nRun the discovery script to extract every package's version and confirm each is published:\n\n    uv run --script .claude/skills/prerelease-test/scripts/check_release_versions.py --ref <git-ref>\n\n(Script paths in this skill are repo-root-relative — the repo has its own unrelated `scripts/`\ndirectory, so the prefix matters.) It exits 1 when a package is confirmed missing and 2 when a\ncheck could not complete, so a proxy hiccup never reads as a missing package. An unpublished\nversion is a finding in its own right — report it immediately rather than working around it.\n\nRead the linked PRs for anything whose intent is not obvious from the changelog line; the GitHub\nMCP tools (`mcp__github__pull_request_read`) do this well. Understanding what a change was *for*\nis what lets you test it as a user rather than as a checklist.\n\n### Phase 1 — De-risk with a smoke test\n\nBefore any fan-out: one venv, `reflex init --template blank`, `reflex run`, then drive it in\nChromium with `.claude/skills/prerelease-test/scripts/drive_app.py`. This shakes out environment\nproblems (proxy, bun installs, browser path) once, in a context where you can debug them, instead\nof inside ten parallel agents.\n\nThe scripts carry PEP 723 metadata, so `uv run --script <path>` runs each one in its own isolated\nenvironment (the driver pulls in playwright that way); running them with an existing driver venv's\ninterpreter works too.\n\nAlso confirm the dependency graph resolves the way the changelog says it should (e.g. optional\ndependencies genuinely absent, sub-packages pinned as intended).\n\n### Phase 2 — Feature exploration fan-out\n\nDecompose the changelog into clusters of related changes and give each to its own agent, with an\nadversarial verification stage behind it. See `references/clusters.md` for how to cut the clusters\nand a standing coverage list; `references/orchestration.md` for the Workflow script, schemas and\nport map.\n\nThe instruction that makes this productive: **real-world exploration, not coverage filling.**\nCombine each new feature with the things users actually combine it with — State vars,\n`rx._x.client_state`, `rx.ComponentState`, `@rx.memo` wrapping, `rx.foreach`/`rx.cond`, event\nchains, background tasks, multiple pages and navigation, dev *and* prod mode. Bugs live in the\ninteractions, and the original PR's tests already cover the happy path.\n\nEvery run inspects all four channels: server log, browser console (errors *and* warnings), network\ntab (failed requests, 4xx/5xx), and the rendered page. Findings frequently show up in a channel\nnobody asserted on.\n\n### Phase 3 — Upgrade regression\n\nUsers upgrade in place; that path has its own failure modes (lockfile migration, pruned packages,\nstale `.web/`). Clone `reflex-dev/reflex-examples`, pick apps that span the feature surface —\nincluding ones using third-party packages (`reflex-local-auth`, `reflex-global-hotkey`) and\n`reflex[db]`/API apps — then for each:\n\n1. Install the **previous stable** (no `--prerelease` flag, so requirements resolve as a user's\n   would), run it, and drive its real user flows in the browser. This is your baseline.\n2. Upgrade the *same* venv and *same* app directory in place to the new version, preserving\n   `.web/` and `reflex.lock/`. Watch the first run's log closely — that is where migration\n   happens. Re-drive the identical flows and compare.\n3. Do one cold run (`rm -rf .web`) to check the fresh-install path converges to the same state.\n\nDiff `.web/package.json` before and after; unexpected dependency changes are findings.\n\n### Phase 4 — Enterprise regression\n\nDownstream breakage is the most common release blocker, because removing a public name is\ninvisible until something imports it. Install the **published** `reflex-enterprise` (never the\ncheckout) against the new reflex and run its demos — ag-grid, map, dnd, mantine, flow, the MCP\nplugin, OIDC. Baseline against the previous stable whenever something fails, so you can say\nwhether the new release broke it.\n\nBefore running anything, grep the published enterprise wheel for names the changelog says moved or\nwere removed; that finds the breakage in seconds instead of hours.\n\n### Phase 5 — Packaging audit\n\nAudit every package in the train; the discovery script feeds it the whole list. Chain the two with\n`&&`, never a pipe — a pipe reports only the audit's exit status, so a package whose PyPI check\nnever completed would be dropped from the list and the audit would still print PASS over what was\nleft. The `&&` is what makes that impossible: the audit runs only when discovery exits 0.\n\n    uv run --script .claude/skills/prerelease-test/scripts/check_release_versions.py \\\n      --ref <ref> --specs > specs.txt \\\n      && xargs uv run --script .claude/skills/prerelease-test/scripts/audit_pyi.py \\\n        --manifest-ref <ref> < specs.txt\n\nIt verifies each package ships its own generated `.pyi` stubs in **both** wheel and sdist, that\nthey are byte-identical between the two, that no package leaks another package's stubs, and that\ncounts line up with `pyi_hashes.json` (a package absent from the manifest must ship none).\n\nStub content hashes legitimately differ from the committed manifest because the build hook\nregenerates them at release time — compare *presence and counts*, and wheel against sdist.\n\n### Phase 6 — Triage and report\n\nWrite `FINDINGS.md` first (everything confirmed), then `RELEASE_PLAN.md` splitting findings into:\n\n**Fix before release** — anything meeting one of:\n- a confirmed regression against the previous stable,\n- security-relevant (path traversal, unauthenticated input handling, injection),\n- significant user impact, or trivially small to fix (a one-line guard, a missing default).\n\n**File as issues, fix after** — everything else, including pre-existing defects the campaign\nhappened to surface. Downstream (enterprise) issues go to that project's tracker, not this repo's.\n\nAlso flag decisions only a maintainer can make — an undocumented behavior change is either a bug\nor a missing changelog entry, and which one it is is their call. Ask rather than assume.\n\n### Phase 7 — Re-verify the next build\n\nWhen a new alpha ships with the fixes, re-run the *original failing repro* for each finding\n(not just the unit tests) against the new published packages, plus a general smoke. Append the\npass/fail table to `FINDINGS.md`. When the final ships, do one last stock-install smoke:\n`pip install reflex==<final>` with no prerelease flag, init, run, browser, and confirm the\nresolved graph is all-final.\n\n## Working rules\n\n- **Isolation.** Every agent gets its own venv and its own reserved port range; never install into\n  a shared venv. See the port map in `references/orchestration.md`.\n- **The traps are real.** `references/agent-brief.md` is the brief to hand every agent — it carries\n  the environment gotchas (checkout shadowing, proxy variables breaking installs) and the list of\n  known-benign console noise. Agents that skip it rediscover the same problems and report noise as\n  findings.\n- **Concurrency.** Dev servers are heavy (bun + vite + granian). On a 4-CPU box run about two\n  agents at a time and one dev server per agent; more just makes everything slow and flaky.\n- **Commit as you go.** Each cluster's artifacts land on the work branch when that cluster\n  finishes, so a long campaign is never one unrecoverable batch.\n- **Never fix framework code during the campaign.** Testing and fixing are separate engagements\n  with separate review standards; mixing them costs you the independence that makes the findings\n  credible. Record the repro and move on. (If the user then asks for fixes, that is a new task —\n  one PR per finding, regression test first, `references/reporting.md` has the PR conventions.)\n\n## Scaling the campaign\n\nFull campaign is roughly 30 agents over several hours. Scale down by dropping whole phases rather\nthan by testing each phase more shallowly — a shallow pass produces false confidence:\n\n- **Quick check** (~30 min): phases 0, 1, 5, plus grep-based downstream checks from phase 4.\n- **Standard** (~2 h): add phase 2 over the three or four highest-risk clusters.\n- **Full**: everything, with adversarial verification on every claimed issue.\n\nAsk the user which they want if the request is ambiguous and the difference matters.\n","isInternal":false,"tokens":2693,"sizeBytes":11850},{"name":"airtable.md","path":"packages/integrations-docs/src/integrations_docs/docs/airtable.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/airtable.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: Data Infrastructure\ndescription: Connect your apps to Airtable to read, create, and update records in real time.\n---\n# Airtable Integration\n\nThe **Airtable Integration** lets your apps interact with Airtable bases to **store, fetch, and update structured data** directly from workflows, user actions, or automated triggers. Perfect for managing dynamic content, customer data, or workflows without complex backend setup.\n\n\n## What You Can Do\n\nWith the Airtable Integration, your app can:\n\n* Read and display data from Airtable bases\n* Create new records dynamically from user actions\n* Update or delete records through workflows\n* Power AI experiences with live database content\n* Sync structured data without hosting your own database\n\n## Step 1: Get Your Airtable API Key\n\n1. Go to [Airtable](https://airtable.com/).\n2. Log in or create a free account.\n3. Navigate to [**Developer Hub**](https://airtable.com/create/tokens) from your account menu.\n4. Under **Personal access tokens**, click **Create token**.\n5. Add the appropriate scopes (e.g. `data.records:read` and `data.records:write`).\n6. Copy your API token.\n   * Example: `patxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n\n1. Click the **Settings** gear icon and navigate to the **Integrations** tab.\n2. Find and enable the **Airtable** integration.\n3. Paste your **API Key** in the input field.\n4. Click **Connect** to confirm the connection.\n\n## Step 3: Use in Your Workflows\n\nOnce connected, you can use Airtable actions in your app to:\n\n* Fetch records to display dynamic lists\n* Add user submissions as new rows\n* Update status fields or metrics from AI workflows\n\nand more.\n\n","frontmatter":{"tags":"Data Infrastructure","description":"Connect your apps to Airtable to read, create, and update records in real time."},"isInternal":false,"tokens":384,"sizeBytes":1678},{"name":"anthropic.md","path":"packages/integrations-docs/src/integrations_docs/docs/anthropic.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/anthropic.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: AI\ndescription: Connect your apps to Anthropic's Claude models for advanced AI capabilities.\n---\n# Anthropic Integration\n\nThe **Anthropic Integration** allows your app to use [Anthropic’s Claude models](https://www.anthropic.com/claude) for tasks such as text generation, summarization, reasoning, and other advanced AI capabilities. Once connected, you can call Claude directly from your workflows, UI actions, or automated triggers.\n\n\n## Step 1: Obtain an Anthropic API Key\n\n1. Go to the [Anthropic Console](https://console.anthropic.com/).\n2. Navigate to **API Keys** in your account settings.\n3. Click **Create Key** and give it a descriptive name (e.g., “AI Builder”).\n4. Copy the generated key.\n\n   * **Example:** `sk-ant-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Anthropic** in your app settings.\n2. Paste your **Anthropic API Key** in the input field.\n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Claude for AI-powered features across workflows and components.\n\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Anthropic API key in public code repositories.\n* **Use environment-specific keys:** Separate dev, staging, and production keys help manage access and security.\n* **Secure API access:** The key allows your app to interact with Anthropic endpoints securely and efficiently.\n\n\n","frontmatter":{"tags":"AI","description":"Connect your apps to Anthropic's Claude models for advanced AI capabilities."},"isInternal":false,"tokens":327,"sizeBytes":1453},{"name":"aws.md","path":"packages/integrations-docs/src/integrations_docs/docs/aws.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/aws.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: Data Infrastructure\ndescription: Connect to Amazon Web Services (AWS) for cloud storage, databases, compute, AI/ML, and more.\n---\n# AWS Integration\n\nThe **AWS Integration** allows your app to connect to [Amazon Web Services (AWS)](https://aws.amazon.com/) — the world's most comprehensive cloud platform. Once connected, your app can access 200+ AWS services including storage, databases, compute, AI/ML, and more using the boto3 SDK.\n\n## What You Can Do\n\nWith AWS integration, your app can:\n- **S3 (Object Storage):** Upload, download, and manage files in S3 buckets. Generate presigned URLs for secure file access. Works with S3-compatible services like MinIO, Cloudflare R2, and DigitalOcean Spaces.\n- **DynamoDB (NoSQL Database):** Store and query data in a fully managed, serverless NoSQL database with single-digit millisecond performance.\n- **Lambda (Serverless Functions):** Invoke serverless functions, run code without managing servers, and build event-driven applications.\n- **SES (Email Service):** Send transactional emails, marketing emails, and notifications with high deliverability.\n- **SNS (Notifications):** Send push notifications, SMS, and email messages to users across multiple channels.\n- **SQS (Message Queues):** Build distributed, decoupled systems with reliable message queuing.\n- **Rekognition (Computer Vision):** Analyze images and videos for object detection, facial analysis, text extraction, and content moderation.\n- **Comprehend (NLP):** Extract insights from text using natural language processing for sentiment analysis, entity recognition, and topic modeling.\n- **Bedrock (AI Models):** Access foundation models from AI21 Labs, Anthropic, Cohere, Meta, Stability AI, and Amazon for generative AI applications.\n- **And 200+ more services:** EC2, RDS, CloudWatch, Polly, Textract, Translate, and many others.\n\n## Step 1: Obtain AWS Credentials\n\n1. Log in to the [AWS Console](https://console.aws.amazon.com/).\n\n2. **Create IAM credentials:**\n   - Navigate to **IAM (Identity and Access Management)**.\n   - Click **Users** → **Add user** or select an existing user.\n   - Attach policies based on the AWS services you plan to use:\n     - **S3:** `AmazonS3FullAccess` or custom S3 policy\n     - **DynamoDB:** `AmazonDynamoDBFullAccess` or custom DynamoDB policy\n     - **Lambda:** `AWSLambdaFullAccess` or custom Lambda policy\n     - **SES:** `AmazonSESFullAccess` or custom SES policy\n     - **Multiple services:** Attach multiple policies or create a custom policy combining permissions\n\n   **Example custom policy for S3 + DynamoDB:**\n   ```json\n   {\n     \"Version\": \"2012-10-17\",\n     \"Statement\": [\n       {\n         \"Effect\": \"Allow\",\n         \"Action\": [\n           \"s3:PutObject\", \"s3:GetObject\", \"s3:DeleteObject\", \"s3:ListBucket\",\n           \"dynamodb:PutItem\", \"dynamodb:GetItem\", \"dynamodb:Query\", \"dynamodb:Scan\"\n         ],\n         \"Resource\": [\n           \"arn:aws:s3:::YOUR_BUCKET_NAME/*\",\n           \"arn:aws:dynamodb:YOUR_REGION:YOUR_ACCOUNT_ID:table/*\"\n         ]\n       }\n     ]\n   }\n   ```\n\n3. **Generate access keys:**\n   - Under **Security credentials**, click **Create access key**.\n   - Choose **Application running outside AWS** as the use case.\n   - Copy your **Access Key ID** and **Secret Access Key**.\n\n   **Example credentials:**\n   * **Access Key ID:** `AKIAIOSFODNN7EXAMPLE`\n   * **Secret Access Key:** `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add AWS** in your app settings.\n2. Enter your **AWS Access Key ID** and **AWS Secret Access Key**.\n3. **(Optional)** Select your **AWS Region** (e.g., `us-east-1`, `eu-west-1`). Defaults to `us-east-1`.\n4. **(Optional)** Enter an **AWS Endpoint URL** if using S3-compatible services:\n   - **MinIO:** `http://localhost:9000` or your MinIO server URL\n   - **Cloudflare R2:** `https://<account-id>.r2.cloudflarestorage.com`\n   - **DigitalOcean Spaces:** `https://<region>.digitaloceanspaces.com`\n   - Leave blank for standard AWS services.\n5. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can access AWS services using boto3.\n\n## Important Notes\n\n* **IAM permissions:** Ensure your IAM user has the necessary permissions for the AWS services you plan to use. Attach service-specific policies (e.g., `AmazonS3FullAccess`, `AmazonDynamoDBFullAccess`, `AWSLambdaFullAccess`) or create custom policies with least-privilege access.\n* **AWS Region:** Most AWS services are region-specific. Select the correct region where your resources are located (e.g., S3 buckets, DynamoDB tables, Lambda functions).\n* **Cost management:** Monitor AWS usage and costs through the AWS Billing Dashboard. Set up billing alerts to avoid unexpected charges.\n* **Security:** Rotate your access keys regularly and enable MFA for AWS console access. Apply least-privilege IAM policies to limit permissions to only what's needed.\n* **S3-compatible services:** For S3 operations, this integration works with S3-compatible storage like MinIO (self-hosted), Cloudflare R2 (zero egress fees), and DigitalOcean Spaces. Just provide the custom endpoint URL in the configuration.\n* **Service availability:** Not all AWS services are available in all regions. Check the [AWS Regional Services List](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/) for service availability.\n","frontmatter":{"tags":"Data Infrastructure","description":"Connect to Amazon Web Services (AWS) for cloud storage, databases, compute, AI/ML, and more."},"isInternal":false,"tokens":1300,"sizeBytes":5414},{"name":"azure_auth.md","path":"packages/integrations-docs/src/integrations_docs/docs/azure_auth.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/azure_auth.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: Authentication\ndescription: Integrate Azure for secure authentication and access management within your application.\n---\n# Azure Auth Manager Integration\n\nThe **Azure Auth Manager Integration** allows your app to authenticate users through Microsoft Azure Active Directory (Azure AD). This integration provides secure OAuth 2.0 authentication and supports multi-tenant applications with customizable tenant access.\n\n## Step 1: Set Up Azure App Registration\n\nBefore connecting, you need to register your app in Azure Portal:\n\n1 - Go to [Azure Portal](https://portal.azure.com) → **App Registrations**\n\n2 - Click **New registration** as shown in the image below:\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_1.webp)\n\n3 - Register your app. Ensure that for the Redirect URI you select **Web** and enter the following URI that you find in the Azure Auth Manager integration settings in AI Builder:\n   ```\n   https://{your-sandbox}/authorization-code/callback\n   ```\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_2.webp)\n\n4 - On the next page get your `client_id` (`AZURE_CLIENT_ID`) and `tenant_id` (`AZURE_VALID_TENANT_IDS`) from the **Overview** tab.\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_3.webp)\n\n5 - Next click `Add a certificate or secret` and copy the generated secret value (`AZURE_CLIENT_SECRET`).\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_4.webp)\n\n\n## Step 2: Configure the Integration\n\n1. Go to the **Integrations** section in your app settings by clicking **`@`** and then clicking the **Integrations** tab at the top.\n2. Click **Add** next to Azure Auth Manager.\n3. Fill in the credential fields:\n   - Enter your Azure Client ID\n   - Enter your Azure Client Secret\n   - Enter valid tenant IDs (comma-separated for multiple tenants)\n4. Click **Connect** to save the integration.\n\nYour app can now authenticate users through Azure AD with secure OAuth 2.0 flow.\n","frontmatter":{"tags":"Authentication","description":"Integrate Azure for secure authentication and access management within your application."},"isInternal":false,"tokens":498,"sizeBytes":2225},{"name":"cartesia.md","path":"packages/integrations-docs/src/integrations_docs/docs/cartesia.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/cartesia.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: AI\ndescription: Add Cartesia’s powerful text-to-speech capabilities for realistic, real-time voice output and audio experiences.\n---\n# Cartesia Integration\n\nThe **Cartesia Integration** allows your app to generate **high-quality, realistic speech from text** using Cartesia’s advanced voice models. Once connected, you can easily add real-time voice capabilities to workflows, user interactions, and automated experiences.\n\n\n## Step 1: Obtain a Cartesia API Key\n\n1. Go to the [Cartesia Console](https://www.cartesia.ai/).  \n2. Log in or create an account.  \n3. Navigate to **API Keys** in your account settings.  \n4. Click **New**, give it a descriptive name (e.g., “AI Builder”), and copy it.  \n   - Example: `sk_car_xxxxxxxxxxxxx`\n\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Open your app and go to **Integrations → Add Cartesia**.  \n2. Paste your **Cartesia API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.  \n\nOnce connected, your app can convert text to speech seamlessly in real time or through workflows.\n\n\n\n## Step 3: Notes\n\n- **Secure API Access:** Keep your Cartesia API key safe. Do not hardcode it in public code.  \n- **Environment isolation:** Use different keys for dev, staging, and production to ensure clean separation.  \n- **Low latency:** Cartesia supports real-time streaming for conversational experiences.  \n- **Usage management:** Monitor your Cartesia dashboard for quotas, billing, and usage insights.\n\n","frontmatter":{"tags":"AI","description":"Add Cartesia’s powerful text-to-speech capabilities for realistic, real-time voice output and audio experiences."},"isInternal":false,"tokens":353,"sizeBytes":1502},{"name":"cohere.md","path":"packages/integrations-docs/src/integrations_docs/docs/cohere.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/cohere.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: AI\ndescription: Add Cohere’s language models for text generation, classification, retrieval, embeddings, and more.\n---\n# Cohere Integration\n\nThe **Cohere Integration** allows your app to use [Cohere’s](https://cohere.com) state-of-the-art language models for natural language understanding and generation. Once connected, your app can power search, summarization, embeddings, classification, and conversational AI features directly from workflows and triggers.\n\n\n## Step 1: Obtain a Cohere API Key\n\n1. Go to the [Cohere Dashboard](https://dashboard.cohere.com/).  \n2. Log in or create an account.  \n3. Navigate to **API Keys** in your account settings.  \n4. Click **Create Key**, give it a descriptive name (e.g., “AI Builder”), and copy the key.  \n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Cohere** in your app settings.  \n2. Paste your **Cohere API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.  \n\nOnce connected, your app can access Cohere’s endpoints for language tasks like embeddings, classification, chat, and more.\n\n\n## Step 3: Notes\n\n- **Secure API Access:** Keep your Cohere API key private — do not hardcode it in public repositories.  \n- **Environment separation:** Use different keys for development, staging, and production environments.  \n- **Performance:** Cohere’s models support fast inference for production-ready experiences.  \n- **Observability:** Use the Cohere dashboard to monitor usage, quotas, and request logs.\n\n","frontmatter":{"tags":"AI","description":"Add Cohere’s language models for text generation, classification, retrieval, embeddings, and more."},"isInternal":false,"tokens":351,"sizeBytes":1547},{"name":"database.md","path":"packages/integrations-docs/src/integrations_docs/docs/database.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/database.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: Data Infrastructure\ndescription: Connect Reflex Build apps to PostgreSQL, MySQL, MSSQL, or SQLite databases.\n---\n# Database Integration\n\nThe Database Integration connects Reflex Build apps to an existing SQL database. When you enable the connection for an app, Reflex Build can inspect its schema and use that structure while generating the app.\n\n## Supported Databases\n\n- **PostgreSQL**\n- **MySQL**\n- **MSSQL** (Microsoft SQL Server)\n- **SQLite**\n\n## Add a Database Integration\n\n1. Open **Integrations** from the project sidebar.\n2. Select **Add Integration**.\n3. Search for and select **Database**.\n4. Configure the connection using **Connection Details** or **Database URI**.\n5. Optionally enter an integration name to distinguish this connection from others in the project.\n6. Select **Save Changes**.\n\nThe integration is saved at the project level. Open an app's **Integrations** panel to enable it for that app when needed.\n\n## Connection Details\n\nUse **Connection Details** to enter each part of the connection separately.\n\nFor PostgreSQL, MySQL, and MSSQL, choose the database type and enter:\n\n- `hostname`: the database server address.\n- `port`: defaults to `5432` for PostgreSQL, `3306` for MySQL, or `1433` for MSSQL.\n- `username` and `password`: the database credentials.\n- `database_name`: the database to connect to.\n\nFor MSSQL, **Trust Server Certificate** skips certificate identity validation. Use it only as a temporary workaround for an untrusted or self-signed server certificate, and prefer configuring a certificate that the client trusts.\n\nFor SQLite, select **SQLite** and enter an HTTP or HTTPS **SQLite Download URL**. Reflex Build downloads the database file before using it.\n\n## Database URI\n\nUse **Database URI** when you have a complete connection URI for one of the supported database types. For example:\n\n```text\npostgresql://username:password@hostname:5432/database_name\n```\n\nEnter the URI in `db_url`, then select **Save Changes**. Reflex Build selects the database driver automatically. Include provider-required connection options as query parameters when needed.\n\n## Connect through an SSH Tunnel\n\nUse an SSH tunnel when the database is on a private network but can be reached through a bastion host. This option is available for PostgreSQL, MySQL, and MSSQL in both connection modes. It is not available for SQLite.\n\n1. Enter the database connection details or URI. Keep the database hostname and port set to the address the bastion host uses to reach the database.\n2. Turn on **Connect via SSH tunnel**.\n3. Enter the `ssh_hostname`, `ssh_port` (usually `22`), and `ssh_username` for the bastion host.\n4. Paste the corresponding PEM-formatted **SSH private key**.\n5. Select **Save Changes**.\n\nThe SSH account must allow port forwarding to the database host and port. Use a dedicated, restricted SSH key and database user for Reflex Build.\n\n```md alert warning\n# Keep credentials private\n\nEnter database passwords, connection URIs, and SSH private keys only in the integration form. Do not put them in prompts, knowledge, source code, or screenshots.\n```\n\n## Enable the Integration for an App\n\nOpen the app's **Integrations** panel and enable the saved database connection. Reflex Build then connects to the database and, when the app does not already have a model file, creates the app's data models from the schema.\n\nIf the connection fails, check that:\n\n- The database or bastion host is reachable.\n- The ports are open and the credentials are valid.\n- The database user can read the schema and has only the data permissions the app needs.\n- The SSH user can forward traffic to the database when tunneling is enabled.\n\n```md alert\n# NoSQL Databases\n\nUse the dedicated MongoDB integration when applicable. For another NoSQL database, add its Python SDK or configure a custom integration; the Database Integration supports SQL databases.\n```\n","frontmatter":{"tags":"Data Infrastructure","description":"Connect Reflex Build apps to PostgreSQL, MySQL, MSSQL, or SQLite databases."},"isInternal":false,"tokens":824,"sizeBytes":3890},{"name":"databricks.md","path":"packages/integrations-docs/src/integrations_docs/docs/databricks.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/databricks.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: Data Infrastructure\ndescription: Connect with Databricks to run data pipelines and advanced analytics seamlessly.\n---\n\n\n# Databricks Integration\n\nThe **Databricks Integration** allows your app to connect to [Databricks](https://www.databricks.com/) for secure data access, querying, and analytics. Once connected, you can run SQL queries, retrieve results, and power data-driven workflows directly from your app.\n\n## What You Can Do\n\nWith Databricks, your app can:\n- Connect securely to your Databricks workspace.  \n- Run **SQL queries** or fetch data programmatically.  \n- Build **dashboards and data visualizations** on top of your Databricks tables.  \n- Automate workflows triggered by new or updated data.  \n- Combine Databricks with AI models for advanced analytics.\n\n\n\n## Step 1: Get Your Databricks Credentials\n\n### 1 - Log in to your [Databricks Workspace](https://databricks.com/).\n\n### 2 - Get your **DATABRICKS_HOST** and **DATABRICKS_WAREHOUSE_ID**:\n\n   - Go to `SQL Warehouses` from the sidebar.\n   - Select your desired warehouse.\n   - Click `Connection details`.\n   - Copy the Server hostname (this is your **DATABRICKS_HOST**).\n   - Copy the HTTP path removing the `/sql/1.0/warehouses/` prefix (this is your **DATABRICKS_WAREHOUSE_ID**).\n\n![Databricks SQL Warehouse connection details](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_1.webp)\n\n### 3 - Get your **DATABRICKS_CATALOG** and **DATABRICKS_SCHEMA**:\n   - Click the SQL Editor from the sidebar.\n   - Choose the **DATABRICKS_CATALOG** and **DATABRICKS_SCHEMA** from the dropdowns as shown below.\n\n![Selecting Databricks catalog and schema in SQL Editor](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_4.webp)\n\n\n### 4 - Obtain your authentication credentials:\n\nThere are two methods to authenticate your app with Databricks: using interactive U2M **OAuth** or via registered M2M **Service Principal**. Choose one of the methods below to obtain the necessary credentials.\n\n\n`````md tabs\n\n## OAuth with Databricks\n\n#### Interactive Login with your Databricks Account\n\nIf your workspace administrator has already added Reflex as a Connected App in your Databricks workspace, you should see a \"Login with Databricks\" button after entering your DATABRICKS_HOST.\n\n\n## Service Principal\n\n#### M2M Service Principal (DATABRICKS_CLIENT_ID and DATABRICKS_CLIENT_SECRET)\n\n- Open the dropdown in the top right corner and select **Manage Account**.\n\n![Opening Manage Account in Databricks](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_1.webp)\n\n- Select `Users and Groups`\n\n![Selecting Users and Groups in Databricks account](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_2.webp)\n\n- Select the `Service Principals` tab and click `Add Service Principal`.\n\n![Adding a Databricks service principal](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_3.webp)\n\n- Fill in the details and click `Add Service Principal`.\n\n![Entering Databricks service principal details](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_4.webp)\n\n- Click the `Credentials and Secrets` tab and click `Generate Secret`.\n\n![Generating a Databricks service principal secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_5.webp)\n\n- Set a lifetime for the secrets and click `Generate`.\n\n![Setting Databricks secret lifetime](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_6.webp)\n\n- Copy the generated **DATABRICKS_CLIENT_ID** and **DATABRICKS_CLIENT_SECRET**.\n\n![Copying Databricks client ID and secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_7.webp)\n\n`````\n\n\n\n## Step 2: Configure the Integration in Your App\n\n1. In your app, go to **Integrations** and **Add Databricks**.\n2. Paste your **DATABRICKS_HOST**\n3. Select your authentication method:\n   - OAuth, if configured.\n   - Service Principal, provide the client ID and secret gathered previously.\n2. Paste or select your\n   1. **DATABRICKS_WAREHOUSE_ID**\n   2. **DATABRICKS_CATALOG**\n   3. **DATABRICKS_SCHEMA**  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, the AI Builder can execute queries directly against your Databricks environment.\n\n\n## Step 3: Notes\n\n* **Secure your token:** Never expose tokens in public code.  \n* **Permissions:** Ensure your token or service account has the required workspace and table permissions.\n* **Combine with AI:** Use query outputs to power models, summaries, or alerts in real time.\n\n\n## How to Enable Login as an Admin\n\n- Login to Databricks\n- Go to manage account\n\n![Opening Manage Account as Databricks admin](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_admin_auth_1.webp)\n\n- Go to **Settings** → **Apps Connections** → **Add new connection**\n\n![Adding a new app connection in Databricks settings](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_admin_auth_2.webp)\n\n- Give it a name, enter the redirect URL that Reflex Build provides, Click `All APIs` and uncheck `Generate a client secret` and then add.\n   - URL: `https://build.reflex.dev/_reflex_oidc_databricks/authorization-code/callback`\n\n![Configuring the Reflex redirect URL in Databricks](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_admin_auth_3.webp)","frontmatter":{"tags":"Data Infrastructure","description":"Connect with Databricks to run data pipelines and advanced analytics seamlessly."},"isInternal":false,"tokens":1414,"sizeBytes":5902},{"name":"descope.md","path":"packages/integrations-docs/src/integrations_docs/docs/descope.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/descope.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: Authentication\ndescription: Add Descope’s identity and authentication platform to your apps to manage user sign-in, onboarding, MFA, SSO, and flows with ease.\n---\n# Descope Integration\n\nThe **Descope Integration** enables your app to leverage Descope’s full Customer Identity & Access Management (CIAM) features—visual authentication flows, identity management, SSO, MFA, tenant isolation, and more. Once set up, you can orchestrate secure user journeys across your application with minimal coding.\n\n\n```md alert warning\n# You must open your app in a new tab from the builder to test the Descope integration.\n```\n\n## What You Can Do\n\nWith Descope Integration, your app can:\n- Handle user sign-up, login, and passwordless flows seamlessly  \n- Enable multifactor authentication (MFA), passkeys, and social login  \n- Support single sign-on (SSO) via OIDC/SAML  \n- Manage users, roles, tenants, and permissions via management APIs  \n- Orchestrate onboarding, branding, and multi-tenant flows via drag-and-drop workflows  \n- Sync user data with tools like HubSpot or Segment via built-in connectors\n\n\n## Step 1: Obtain Descope Credentials\n\n![Descope Credentials](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/descope.webp)\n\n1. Log in to the [**Descope Console** (or sign up)](https://www.descope.com/sign-up).\n2. Create your first Project. \n3. Go to the Project page under Settings.\n4. Copy the `Project ID`.\n\n\n## Step 2: Configure the Integration in Your App\n\n1. In your app’s settings or integration dashboard, select **Add Descope**.  \n2. Enter your **PROJECT_ID**.  \n3. (Optional) Pick a **DESCOPE_FLOW_ID** (e.g. “sign-up-or-login”) and **SESSION_SECRET_KEY** or press the Clipboard Copy to use default values.  \n4. Click **Connect** to validate credentials and enable Descope features.\n\n![Descope Integration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/descope_2.webp)\n\n\n","frontmatter":{"tags":"Authentication","description":"Add Descope’s identity and authentication platform to your apps to manage user sign-in, onboarding, MFA, SSO, and flows with ease."},"isInternal":false,"tokens":469,"sizeBytes":1987},{"name":"gemini.md","path":"packages/integrations-docs/src/integrations_docs/docs/gemini.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/gemini.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: AI\ndescription: Connect your apps to Google’s Gemini models for advanced AI capabilities.\n---\n# Gemini Integration\n\nThe **Gemini Integration** allows your app to use [Google’s Gemini models](https://aistudio.google.com/) for text generation, reasoning, multimodal analysis, and other advanced AI capabilities. Once connected, you can call Gemini directly from your workflows, UI actions, or automated triggers.\n\n## Step 1: Obtain a Gemini API Key\n\n1. Go to [Google AI Studio](https://aistudio.google.com/).\n2. Navigate to **Get API Key** or create a new key for your project.\n3. Copy the generated key.\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Gemini** in your app settings.  \n2. Paste your **Gemini API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Gemini for AI-powered features across workflows and components.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Gemini API key in public code repositories.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys help manage access and security.  \n* **Secure API access:** The key allows your app to interact with Gemini endpoints securely and efficiently.\n","frontmatter":{"tags":"AI","description":"Connect your apps to Google’s Gemini models for advanced AI capabilities."},"isInternal":false,"tokens":285,"sizeBytes":1285},{"name":"github.md","path":"packages/integrations-docs/src/integrations_docs/docs/github.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/github.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: Developer Tools\ndescription: Connect your app to GitHub to automate workflows, manage repositories, and integrate developer operations.\n---\n# GitHub Integration\n\nThe **GitHub Integration** lets your app connect directly to [GitHub](https://github.com) to automate actions, fetch data, and build powerful developer workflows. Once connected, your app can interact with repositories, issues, pull requests, and more.\n\n## What You Can Do\n\nWith GitHub, your app can:\n- Fetch and display repository data (commits, branches, issues, etc.).  \n- Create or update issues, pull requests, and discussions.  \n- Trigger workflows or CI/CD pipelines.  \n- Sync GitHub activity into your app’s dashboards or automations.  \n- Build custom developer tools using GitHub’s API.\n\n## Step 1: Generate a Personal Access Token\n\n1. Go to your [GitHub Settings](https://github.com/settings/tokens).  \n2. Navigate to **Developer settings → Personal access tokens**.  \n3. Click **Generate new token** (classic or fine-grained).  \n4. Select the required scopes (e.g., `repo`, `workflow`, `read:user`).  \n5. Copy the token.  \n   **Example token:**  \n```\nghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n```\n(Note: Replace the above value with your actual GitHub token)\n\n> 💡 Fine-grained tokens are recommended for better security.\n\n## Step 2: Configure the Integration in Your App\n\n1. In your app, go to **Integrations → Add GitHub**.  \n2. Paste your **GitHub Personal Access Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can start interacting with GitHub through workflows and actions.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Never expose your GitHub token in public code.  \n* **Use fine-grained permissions:** Limit access to only what’s needed.  \n* **API rate limits:** GitHub imposes API limits, so plan automations accordingly.  \n* **Combine with AI:** For example, auto-generate release notes from commits or summarize PRs with LLMs.\n\n","frontmatter":{"tags":"Developer Tools","description":"Connect your app to GitHub to automate workflows, manage repositories, and integrate developer operations."},"isInternal":false,"tokens":447,"sizeBytes":2005},{"name":"google_auth.md","path":"packages/integrations-docs/src/integrations_docs/docs/google_auth.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/google_auth.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: Authentication\ndescription: Enable secure authentication using Google sign-in and OAuth 2.0 workflows.\n---\n\n# Google Auth Integration\n\nThe **Google Auth Integration** allows your app to authenticate users using their Google accounts. This provides a secure, familiar login experience and simplifies user management.\n\n\n## Step 1: Create a Google OAuth Client\n\n1 - Go to the [Google Cloud Console](https://console.cloud.google.com/)\n\n2 - Navigate to **APIs & Services → Credentials**\n\n3 - Click **Create Credentials**\n\n![Creating credentials in Google Cloud Console](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_1.webp)\n\n4 - Choose **OAuth client ID**.\n\n![Choosing OAuth client ID credential type](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_2.webp)\n\n5 - Choose **Web Application** as the application type, name the application and enter your sandbox URL, which you get from the Google Auth integration panel, as the **Authorized JavaScript Origin** and **Authorized Redirect URIs**.\n\n![Configuring Google OAuth web application origins](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_3.webp)\n\n6 - Copy the generated **Client ID** (`GOOGLE_CLIENT_ID`) and **Client Secret** (`GOOGLE_CLIENT_SECRET`).\n\n![Copying Google client ID and secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_4.webp)\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Google Auth** in your app settings.\n2. Enter your **Google Client ID** and **Google Client Secret**.\n3. Save the integration. Your app is now configured to use Google Auth for login.\n\n## Step 3: Notes\n\n- The integration supports multiple environments (development, staging, production). Use environment-specific secrets for the client ID and secret.\n- Google Auth handles token refresh automatically when users log in via OAuth.\n- Users will see a standard Google login screen, ensuring familiarity and trust.\n- Ensure your app domain matches the authorized JavaScript origin and redirect URIs; otherwise, authentication will fail.\n","frontmatter":{"tags":"Authentication","description":"Enable secure authentication using Google sign-in and OAuth 2.0 workflows."},"isInternal":false,"tokens":475,"sizeBytes":2249},{"name":"groq.md","path":"packages/integrations-docs/src/integrations_docs/docs/groq.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/groq.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: AI\ndescription: Connect your apps to Groq’s ultra-fast inference API for lightning-speed AI responses.\n---\n# Groq Integration\n\nThe **Groq Integration** allows your app to use [Groq’s API](https://groq.com/) for ultra-fast AI inference. Once connected, your app can leverage Groq’s hosted models (including open models like Llama 4 and Qwen) to power real-time workflows, chat experiences, and other AI-driven features.\n\n## Step 1: Obtain a Groq API Key\n\n1. Go to the [Groq Console](https://console.groq.com/).  \n2. Navigate to **API Keys** in your account settings.  \n3. Click **Create API Key** and give it a descriptive name (e.g., “AI Builder”).  \n4. Copy the generated key.\n   * **Example:** `gsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Groq** in your app settings.  \n2. Paste your **Groq API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Groq to deliver ultra-low latency AI responses across workflows and components.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Groq API key in public code repositories.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys help manage access and security.  \n* **Secure API access:** The key allows your app to interact with Groq endpoints securely and efficiently.\n","frontmatter":{"tags":"AI","description":"Connect your apps to Groq’s ultra-fast inference API for lightning-speed AI responses."},"isInternal":false,"tokens":343,"sizeBytes":1430},{"name":"hubspot.md","path":"packages/integrations-docs/src/integrations_docs/docs/hubspot.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/hubspot.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: Data Infrastructure\ndescription: Connect your apps to HubSpot to manage contacts, companies, deals, and marketing workflows.\n---\n# HubSpot Integration\n\nThe **HubSpot Integration** allows your app to use [HubSpot](https://www.hubspot.com/) as a CRM and marketing automation platform. Once connected, your app can sync leads, manage contacts, update pipelines, and trigger workflows directly from user actions or automated events.\n\n## Step 1: Obtain a HubSpot Access Token\n\n1. Go to your [HubSpot Developer Account](https://developers.hubspot.com/).  \n2. Navigate to **App → Private Apps** in your account settings.  \n3. Click **Create Private App**, configure scopes (e.g., `crm.objects.contacts.read/write`, `crm.schemas.companies.read`), and save.  \n4. Copy the **Access Token** from the Auth tab.\n   * **Example:** `pat-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add HubSpot** in your app settings.  \n2. Paste your **HubSpot Access Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can sync and manage HubSpot data directly from workflows and UI actions.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Do not hardcode your HubSpot token in public code repositories.  \n* **Use environment-specific tokens:** Separate dev, staging, and production tokens to manage access.  \n* **Secure API access:** The token allows your app to interact with HubSpot endpoints securely and efficiently.\n\n","frontmatter":{"tags":"Data Infrastructure","description":"Connect your apps to HubSpot to manage contacts, companies, deals, and marketing workflows."},"isInternal":false,"tokens":352,"sizeBytes":1541},{"name":"hugging_face.md","path":"packages/integrations-docs/src/integrations_docs/docs/hugging_face.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/hugging_face.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: AI\ndescription: Connect your apps to Hugging Face to access thousands of open models for text, vision, and multimodal tasks.\n---\n# Hugging Face Integration\n\nThe **Hugging Face Integration** allows your app to use [Hugging Face](https://huggingface.co/) models for a wide range of AI tasks — including text generation, embeddings, translation, classification, image processing, and more. You can integrate both hosted models (via API) or local open-source models through the Transformers library.\n\n## What You Can Do\n\nWith Hugging Face, your app can:\n- Access thousands of pre-trained **text, vision, and multimodal models**.  \n- Run **text generation**, summarization, translation, and classification tasks.  \n- Use **embeddings** for search, retrieval, and similarity.  \n- Deploy models locally with `transformers` or connect to hosted inference endpoints.  \n- Fine-tune or customize open models for your specific use cases.  \n- Integrate community and enterprise models seamlessly into workflows.\n\n## Step 1: Obtain a Hugging Face Access Token (Optional)\n\n1. Go to [Hugging Face](https://huggingface.co/).  \n2. Log in or create a free account.  \n3. Navigate to **Settings → Access Tokens**.  \n4. Click **Create New token**, set its scope, and copy it.\n   * **Example:** `hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Hugging Face** in your app settings.  \n2. Paste your **Hugging Face Access Token** if required.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Hugging Face models directly in workflows, UI actions, or automations.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Never expose your Hugging Face token in client-side code.  \n* **Use environment-specific tokens:** Separate dev, staging, and production access.  \n* **Open-source flexibility:** Models can be run fully locally or through Hugging Face’s hosted endpoints.  \n* **Broad ecosystem:** Hugging Face supports thousands of community and commercial models for rapid prototyping and production use.\n","frontmatter":{"tags":"AI","description":"Connect your apps to Hugging Face to access thousands of open models for text, vision, and multimodal tasks."},"isInternal":false,"tokens":471,"sizeBytes":2110},{"name":"langchain.md","path":"packages/integrations-docs/src/integrations_docs/docs/langchain.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/langchain.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: AI\ndescription: Connect your apps to Langchain for advanced AI capabilities.\n---\n# Langchain Integration\nThe **LangChain Integration** allows your app to leverage the power of [LangChain](https://langchain.com/), a popular open-source framework for building applications with large language models (LLMs). Once connected, your app can orchestrate complex AI workflows, chain together multiple model calls, and integrate with various data sources and tools seamlessly.\n\n\nYou can:\n\n* **Chain model calls together** to create multi-step reasoning flows.\n* **Connect multiple providers** (e.g., OpenAI, Anthropic, Gemini, Groq) through a single interface.\n* **Build intelligent agents** that can use tools, call APIs, or access external data sources dynamically.\n* **Work with structured data** by combining LLMs with databases, vector stores, and retrieval systems.\n* **Create RAG (Retrieval-Augmented Generation)** pipelines to ground model outputs in your own data.\n* **Integrate tools and memory** so models can reason over past interactions and context.\n* **Deploy reusable components** like prompt templates, chains, and agents for production-grade applications.\n\nLangChain essentially acts as a **“glue layer”** between language models, data, and logic — enabling teams to build more **powerful and reliable AI apps** without reinventing core orchestration features.\n\n\n## Configure the Integration in Your App\n\n1. Click the **Settings** gear icon and navigate to the **Integrations** tab.\n2. Find and enable the **LangChain** integration.\n\n","frontmatter":{"tags":"AI","description":"Connect your apps to Langchain for advanced AI capabilities."},"isInternal":false,"tokens":322,"sizeBytes":1559},{"name":"linear.md","path":"packages/integrations-docs/src/integrations_docs/docs/linear.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/linear.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: DevTools\ndescription: Connect your apps to Linear to manage issues, projects, and sprints directly from workflows.\n---\n# Linear Integration\n\nThe **Linear Integration** allows your app to connect to [Linear](https://linear.app/) to create, update, and track issues and projects seamlessly. Once connected, your app can trigger Linear actions from user interactions or automated workflows.\n\n## What You Can Do\n\nWith Linear, your app can:\n- **Create and assign issues** automatically from user actions or AI workflows.  \n- **Update status and priority** of tickets and projects.  \n- **Sync with sprints and cycles** to keep work organized.  \n- **Fetch project and issue data** for dashboards, summaries, or automation.  \n- **Integrate with other tools** like Slack or GitHub through workflows.  \n- Power intelligent workflows (e.g., auto-triage or auto-summarize bug reports).\n\n## Step 1: Obtain a Linear API Key\n\n1. Go to your [Linear account](https://linear.app/).  \n2. Navigate to **Workspace Settings → API**.  \n3. Click **Create API Key**, give it a name, and copy the key.\n\n   * **Example:** `lin_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Linear** in your app settings.\n2. Paste your **Linear API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can interact with Linear to automate issue tracking and project management.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Never expose your Linear API key in client-side code.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys.  \n* **Streamlined workflows:** Automate ticket creation, status updates, and reporting directly from your app.  \n* **Real-time visibility:** Fetch and sync project data to power internal tools or dashboards.\n\n","frontmatter":{"tags":"DevTools","description":"Connect your apps to Linear to manage issues, projects, and sprints directly from workflows."},"isInternal":false,"tokens":418,"sizeBytes":1874},{"name":"notion.md","path":"packages/integrations-docs/src/integrations_docs/docs/notion.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/notion.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: Data Infrastructure\ndescription: Connect your apps to Notion to create, update, and query pages, databases, and documents.\n---\n# Notion Integration\n\nThe **Notion Integration** allows your app to connect to [Notion](https://www.notion.so/) to manage content, automate workflows, and build dynamic interfaces on top of Notion workspaces. Once connected, your app can read and write pages, sync databases, and trigger actions based on user activity.\n\n## What You Can Do\n\nWith Notion, your app can:\n- **Create and update pages** in workspaces automatically.  \n- **Read and query databases** to power dashboards, workflows, or automations.  \n- **Sync structured content** like tasks, notes, or documentation with other tools.  \n- Trigger **actions from AI workflows** (e.g., creating meeting notes, logging issues).  \n- Integrate with other services (e.g., Slack, Linear, HubSpot) for seamless collaboration.\n\n## Step 1: Obtain a Notion API Token\n\n1. Go to the [Notion Developers](https://www.notion.so/my-integrations) page.  \n2. Click **+ New Integration**, give it a name, and copy the generated **Internal Integration Token**.  \n3. Share the integration with the relevant pages or databases in your workspace to grant access.\n\n   * **Example:** `ntn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Notion** in your app settings.  \n2. Paste your **Notion API Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can read and write to Notion directly from workflows and UI actions.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Never expose your Notion token in client-side code.  \n* **Use environment-specific tokens:** Separate dev, staging, and production access.  \n* **Granular permissions:** Only share the integration with the pages or databases it needs to access.  \n* **Powerful building block:** Use Notion as a single source of truth for content, tasks, or structured data.\n\n","frontmatter":{"tags":"Data Infrastructure","description":"Connect your apps to Notion to create, update, and query pages, databases, and documents."},"isInternal":false,"tokens":464,"sizeBytes":2027},{"name":"okta_auth.md","path":"packages/integrations-docs/src/integrations_docs/docs/okta_auth.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/okta_auth.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: Authentication\ndescription: Use Okta for secure identity and access management via Single Sign-On provisioning.\n---\n\n# Okta Auth Manager Integration\n\nThe **Okta Auth Manager Integration** allows your app to authenticate users through [Okta](https://okta.com). This integration provides secure OAuth 2.0 / OIDC authentication and supports multi-tenant environments with customizable access policies.\n\n\n## What You Can Do\n\nWith Okta, your app can:\n- Authenticate users securely through Okta’s identity platform.  \n- Enable **SSO** for enterprise users.  \n- Manage user roles, groups, and access permissions.  \n- Protect sensitive data and actions with **OAuth 2.0** and **OpenID Connect (OIDC)**.  \n- Integrate with other identity workflows like MFA or adaptive policies.\n\n\n## Step 1: Set Up Okta OIDC App\n\nBefore connecting, you need to create an OIDC application in the Okta Admin Console:\n\n1 - Go to [Okta Admin Console](https://login.okta.com) → **Applications** → **Applications**\n\n\n2 - Click **Create App Integration**\n\n![Creating an Okta app integration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_1.png)\n\n3 - Select **OIDC – OpenID Connect** and choose **Web Application**\n\n![Selecting OIDC web application in Okta](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_2.png)\n\n4 - Configure your app settings:\n   - **Allow wildcard * in sign-in redirect URIs**\n   - **Sign-in redirect URIs** found in the Okta Auth Manager integration settings in AI Builder:\n     `https://{your-sandbox}/authorization-code/callback`\n   - **Sign-out redirect URIs**:\n     `https://{your-sandbox}`\n   - Assign to the correct **Group** or **Everyone** depending on your access control\n\n![Configuring Okta sign-in redirect URIs](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_3.png)\n\n5 - Save the app integration.\n\n6 - Copy your **Client ID** (`OKTA_CLIENT_ID`) and **Client Secret** (`OKTA_CLIENT_SECRET`) from the app settings.\n\n![Copying Okta client ID and secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_4.png)\n\n\n## Step 2: Finding Your Okta Issuer URI\n\n1. In the Okta Admin Console, go to **Security** → **API** → **Authorization Servers**\n2. Click on the **default** server and copy the **Issuer URI**.\n3. Remove the trailing `/oauth2/default` from the URI to get your **Okta Issuer URI** (`OKTA_ISSUER_URI`).\n\nExample:\n\nIf your Issuer URI is `https://{yourOktaDomain}.okta.com/oauth2/default`\n\nUse `https://{yourOktaDomain}.okta.com`\n\n![Finding the Okta issuer URI](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_5.png)\n\n\n> **Note:** Always use separate Okta apps for dev, staging, and production environments to avoid mixing credentials.\n\n\n## Step 3: Configure the Integration\n\n1. Go to the **Integrations** section in your app settings by clicking **`@`** and then selecting the **Integrations** tab.\n2. Click **Add** next to **Okta Auth Manager**.\n3. Fill in the credential fields:\n   - Enter your Okta Client ID\n   - Enter your Okta Client Secret\n   - Enter your Okta Issuer URI\n4. Click **Connect** to save the integration.\n\nYour app can now authenticate users through Okta using the secure OAuth 2.0 / OIDC flow.\n","frontmatter":{"tags":"Authentication","description":"Use Okta for secure identity and access management via Single Sign-On provisioning."},"isInternal":false,"tokens":834,"sizeBytes":3409},{"name":"openai.md","path":"packages/integrations-docs/src/integrations_docs/docs/openai.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/openai.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: AI\ndescription: Connect to OpenAI's powerful language models for text generation, analysis, and more.\n---\n# OpenAI Integration\n\nThe **OpenAI Integration** allows your app to use OpenAI APIs for features such as text generation, embeddings, and other AI-powered functionality.\n\n## Step 1: Obtain an OpenAI API Key\n\n1. Go to the [OpenAI Platform](https://platform.openai.com/).\n2. Navigate to **API Keys** in your account settings.\n3. Click **Create new secret key**.\n4. Copy the generated key.\n   - Example: `sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add OpenAI Integration** in your app settings.\n2. Enter your **OpenAI API Key** in the input field.\n3. Save the integration. Your app is now ready to make OpenAI API requests.\n\n---\n\n## Step 3: Notes\n\n- Keep your OpenAI key secure; do **not** hardcode it in public code repositories.\n- Use environment-specific secrets if you have separate development, staging, and production environments.\n- The key allows your app to interact with OpenAI endpoints securely and efficiently.\n","frontmatter":{"tags":"AI","description":"Connect to OpenAI's powerful language models for text generation, analysis, and more."},"isInternal":false,"tokens":258,"sizeBytes":1115},{"name":"overview.md","path":"packages/integrations-docs/src/integrations_docs/docs/overview.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/overview.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"```python exec\nfrom pcweb.pages.integrations.integration import integration_page\n```\n\n```python eval\nintegration_page()\n```\n","isInternal":false,"tokens":27,"sizeBytes":124},{"name":"perplexity.md","path":"packages/integrations-docs/src/integrations_docs/docs/perplexity.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/perplexity.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: AI\ndescription: Connect your apps to Perplexity to power real-time, retrieval-augmented AI experiences.\n---\n# Perplexity Integration\n\nThe **Perplexity Integration** allows your app to use [Perplexity](https://www.perplexity.ai/) to deliver fast, accurate, retrieval-augmented answers from the web and trusted sources. Once connected, you can use Perplexity to enhance search, summarization, and real-time knowledge in your workflows.\n\n## What You Can Do\n\nWith Perplexity, your app can:\n- **Retrieve real-time information** from the web to ground model outputs.  \n- **Generate concise summaries** and answers with citations.  \n- Power **search experiences**, research assistants, and contextual AI features.  \n- **Combine Perplexity with other models** for hybrid workflows (e.g., retrieval + reasoning).  \n- Enable **trusted, source-backed outputs** for more accurate responses.\n\n## Step 1: Obtain a Perplexity API Key\n\n1. Go to the [Perplexity](https://www.perplexity.ai/).  \n2. Log in or create an account.  \n3. Navigate to **Account → API → [API Keys](https://www.perplexity.ai/account/api/keys)**.  \n4. Click **Generate Key** and copy the generated key.\n\n   * **Example:** `pplx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Perplexity** in your app settings.  \n2. Paste your **Perplexity API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Perplexity for retrieval-augmented AI features across workflows and components.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Perplexity API key in public code repositories.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys for better control.  \n* **Secure API access:** The key allows your app to interact with Perplexity endpoints securely and efficiently.  \n* **Real-time power:** Perplexity is ideal for use cases where freshness and factual grounding matter.\n","frontmatter":{"tags":"AI","description":"Connect your apps to Perplexity to power real-time, retrieval-augmented AI experiences."},"isInternal":false,"tokens":470,"sizeBytes":2021},{"name":"replicate.md","path":"packages/integrations-docs/src/integrations_docs/docs/replicate.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/replicate.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: AI\ndescription: Connect your apps to Replicate to run and deploy open-source machine learning models with ease.\n---\n# Replicate Integration\n\nThe **Replicate Integration** allows your app to use [Replicate](https://replicate.com/) to run open-source AI models in the cloud without managing infrastructure. Once connected, you can use Replicate to generate text, images, audio, and more — directly from workflows and UI actions.\n\n## What You Can Do\n\nWith Replicate, your app can:\n- Run open-source **AI models** without GPU or hosting setup.  \n- Access models for **text generation**, **image generation**, **audio**, and **multimodal tasks**.  \n- Automate workflows like content generation, data processing, or AI-powered features.  \n- Use prebuilt models or deploy your own custom models.  \n- Scale effortlessly with serverless infrastructure.\n\n## Step 1: Obtain a Replicate API Token\n\n1. Go to the [Replicate Dashboard](https://replicate.com/account).  \n2. Log in or create an account.\n3. Navigate to the **API Tokens** section.  \n4. Copy your **API Token** from the account page.\n\n   * **Example:** `r8_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Replicate** in your app settings.  \n2. Paste your **Replicate API Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can call Replicate models directly in workflows, UI actions, or automations.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Do not hardcode your Replicate token in public code repositories.  \n* **Use environment-specific tokens:** Separate dev, staging, and production environments for security.  \n* **Secure API access:** The token allows your app to interact with Replicate endpoints safely and efficiently.  \n* **Model flexibility:** You can use community models or deploy your own for full control.\n","frontmatter":{"tags":"AI","description":"Connect your apps to Replicate to run and deploy open-source machine learning models with ease."},"isInternal":false,"tokens":429,"sizeBytes":1921},{"name":"resend.md","path":"packages/integrations-docs/src/integrations_docs/docs/resend.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/resend.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: Communication\ndescription: Send transactional and automated emails directly from your AI-generated applications using Resend.\n---\n# Resend Integration\n\nThe **Resend Integration** allows your AI-generated apps to send emails directly from workflows, user actions, or automated triggers — perfect for notifications, confirmations, or any email-based communication your app needs.\n\n\n## What You Can Do\n\nWith the Resend Integration, your app can:\n- Send automated transactional emails\n- Notify users of important events (signups, job completions, etc.)\n- Integrate email sending into AI workflows\n- Use dynamic variables in your message body (e.g. user name, order ID)\n\n## Step 1: Get Your Resend API Key\n\n1. Go to [Resend](https://resend.com/).\n2. Log in or create a free account.\n3. Navigate to **API Keys** from the dashboard sidebar.\n4. Click **Create API Key**, give it a name (e.g. “AI Builder”), and copy it.\n   - Example: `re_xxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Open your app in the **AI Builder**.\n2. Click the **Settings** gear icon and navigate to the **Integrations** tab.\n3. Find and enable the **Resend** integration.\n4. Paste your **API Key** in the input field.\n5. Click **Connect** to confirm the connection.\n","frontmatter":{"tags":"Communication","description":"Send transactional and automated emails directly from your AI-generated applications using Resend."},"isInternal":false,"tokens":302,"sizeBytes":1286},{"name":"roboflow.md","path":"packages/integrations-docs/src/integrations_docs/docs/roboflow.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/roboflow.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: AI\ndescription: Connect your apps to Roboflow to use computer vision models and datasets for image detection, classification, and segmentation.\n---\n# Roboflow Integration\n\nThe **Roboflow Integration** allows your app to use [Roboflow](https://roboflow.com/) to run and deploy computer vision models without complex infrastructure. Once connected, you can use Roboflow to power image detection, object tracking, classification, and segmentation workflows.\n\n## What You Can Do\n\nWith Roboflow, your app can:\n- Run **pre-trained computer vision models** for detection, classification, or segmentation.  \n- Deploy and use **custom-trained models** built in Roboflow.  \n- Automate workflows that rely on visual inputs — e.g., quality checks, object detection, image analysis.  \n- Ingest and process **images in real time**.  \n- Combine vision outputs with other integrations (e.g., AI reasoning, automation flows).\n\n```md alert\n## This integration currently supports image inputs only.\nVideo and streaming inputs are not yet supported.\n```\n\n## Step 1: Obtain a Roboflow API Key\n\n1. Go to your [Roboflow Account](https://roboflow.com/).\n2. Navigate to **Settings → API Keys**.  \n3. Copy your Private API Key.\n\n\n## Step 2: Set up your Model in Roboflow\n\n1. Go to Workflows and create a new workflow.\n2. Set up the workflow you want to use in your app, ensuring that it takes an image as input.\n3. Click the `deploy` button, select `Images` and then select `Integrate with my app or website`.\n4. Copy the `workspace_name` and `workflow_id` from the provided code snippet.\n\n![Roboflow](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/roboflow.webp)\n\n## Step 3: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Roboflow** in your app settings.  \n2. Paste your **Roboflow API Key**, **Workspace Name**, and **Workflow ID** in the input fields.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can call Roboflow models directly from workflows, UI actions, or automated triggers.\n\n\n## Step 4: Notes\n\n* **Keep your key secure:** Never expose your Roboflow key in client-side code.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys to control access.  \n* **Model flexibility:** Use community models or your own custom-trained models.  \n* **Real-time vision:** Ideal for applications involving cameras, inspection, monitoring, or visual AI.\n","frontmatter":{"tags":"AI","description":"Connect your apps to Roboflow to use computer vision models and datasets for image detection, classification, and segmentation."},"isInternal":false,"tokens":575,"sizeBytes":2474},{"name":"snowflake.md","path":"packages/integrations-docs/src/integrations_docs/docs/snowflake.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/snowflake.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"# Snowflake\n\nSnowflake is a cloud-based data warehousing platform that enables users to store, manage, and analyze large volumes of data. It provides a scalable and flexible architecture that separates storage and compute resources, allowing for efficient data processing and querying.\n\nThe integration supports two authentication methods: **OAuth** (each user logs in with their own Snowflake account) and **Key Pair** (the app authenticates as a shared service user with an RSA key pair — no browser login, tokens never expire mid-session).\n\n## OAuth\n\n### Step 1: Create an OAuth Integration in Snowflake\n\nTo enable OAuth for your Snowflake account, an administrator must first register the connected app.\n\n```python exec\nimport reflex as rx\nfrom flexgen.ui.components.markdown import get_base_component_map\n\ntry:\n    from flexgen.integrations.snowflake import SnowflakeAuthState\nexcept ImportError:\n    redirect_uri = (\n        \"https://build.reflex.dev/_reflex_oidc_snowflake/authorization-code/callback\"\n    )\nelse:\n    redirect_uri = SnowflakeAuthState.redirect_uri\n```\n\n```python eval\n# Actually render the real redirect_uri for copy/paste\nget_base_component_map()[\"pre\"](\n    f\"\"\"CREATE SECURITY INTEGRATION oauth_reflex_build_int\n  TYPE = OAUTH\n  ENABLED = TRUE\n  OAUTH_CLIENT = CUSTOM\n  OAUTH_CLIENT_TYPE = 'PUBLIC'\n  OAUTH_REDIRECT_URI = '{redirect_uri}'\n  OAUTH_ISSUE_REFRESH_TOKENS = TRUE\n  OAUTH_REFRESH_TOKEN_VALIDITY = 86400;\"\"\",\n    language=\"sql\",\n)\n```\n\n### Step 2: Log in via OAuth\n\nNOTE: you must use a non-admin account to complete the OAuth flow.\n\n## Key Pair\n\nKey-pair authentication connects as a Snowflake service user with a registered RSA public key. Use it when the app should have its own identity instead of a user's OAuth session.\n\n### Step 1: Generate an RSA key pair\n\nGenerate an unencrypted PKCS#8 private key:\n\n```bash\nopenssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt\n```\n\nOr generate an encrypted one, if your organization requires passphrase-protected keys at rest:\n\n```bash\nopenssl genrsa 2048 | openssl pkcs8 -topk8 -v2 aes256 -inform PEM -out rsa_key.p8\n```\n\nThen derive the public key:\n\n```bash\nopenssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub\n```\n\n### Step 2: Register the public key on a Snowflake user\n\nRun as an administrator, pasting the contents of `rsa_key.pub` without the `BEGIN/END PUBLIC KEY` lines:\n\n```sql\nCREATE USER IF NOT EXISTS svc_reflex TYPE = SERVICE DEFAULT_ROLE = <role>;\nGRANT ROLE <role> TO USER svc_reflex;\n\nALTER USER svc_reflex SET RSA_PUBLIC_KEY='MIIBIjANBgkq...';\n```\n\nTo print the `ALTER USER` statement with the key already formatted on a single line:\n\n```bash\necho \"ALTER USER svc_reflex SET RSA_PUBLIC_KEY='$(grep -v '^-----' rsa_key.pub | tr -d '\\n')';\"\n```\n\nThe `GRANT ROLE` is required — `DEFAULT_ROLE` only sets a preference and does not grant the role. The role needs `USAGE` on the warehouse, database, and schema the app will query. To verify the registration, compare `RSA_PUBLIC_KEY_FP` from `DESC USER svc_reflex` (Snowflake prefixes it with `SHA256:`) against the output of:\n\n```bash\nopenssl rsa -pubin -in rsa_key.pub -outform DER | openssl dgst -sha256 -binary | openssl enc -base64\n```\n\n### Step 3: Fill in the Key Pair tab\n\n- `SNOWFLAKE_USER`: the user the public key is registered on (e.g. `svc_reflex`)\n- `SNOWFLAKE_PRIVATE_KEY`: paste the full contents of `rsa_key.p8` (mangled newlines from copy/paste are fine)\n- `SNOWFLAKE_PRIVATE_KEY_PASSPHRASE`: only if the private key is encrypted. It is stored with the integration secrets and used to decrypt the key at connect time. To strip a passphrase from an existing key instead: `openssl pkcs8 -topk8 -in rsa_key.p8 -nocrypt -out rsa_key_plain.p8`\n\nThe warehouse and database dropdowns populate once the key pair authenticates, which doubles as a connection check.\n\nIf a private key is ever lost or leaked, generate a new pair and re-run the `ALTER USER ... SET RSA_PUBLIC_KEY` — Snowflake also supports `RSA_PUBLIC_KEY_2` for zero-downtime rotation.\n\n# Roadmap \n\nIn the future, this integration will be extended to support external OAuth\nflows, service principal authentication, and external network access.\n","isInternal":false,"tokens":1034,"sizeBytes":4191},{"name":"stripe.md","path":"packages/integrations-docs/src/integrations_docs/docs/stripe.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/stripe.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ndescription: Connect your apps to Stripe to accept payments, manage subscriptions, and handle billing securely.\n---\n# Stripe Integration\n\nThe **Stripe Integration** allows your app to use [Stripe](https://stripe.com/) to power secure payments, subscriptions, and billing workflows. Once connected, you can process transactions, manage customers, and trigger payment flows directly from your app.\n\n## What You Can Do\n\nWith Stripe, your app can:\n- **Accept one-time payments** or set up **recurring subscriptions**.  \n- **Manage customers**, payment methods, and invoices.  \n- Handle **refunds, payment confirmations**, and notifications.  \n- Automate billing flows and webhook-based actions.  \n- Build secure, PCI-compliant checkout experiences with ease.\n\n## Step 1: Obtain a Stripe API Key\n\n1. Go to your [Stripe Dashboard](https://dashboard.stripe.com/).  \n2. Navigate to **Developers → API Keys**.  \n3. Copy your **Secret Key** (or create a restricted key for added security).\n\n   * **Example:** `sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n> 💡 Use test keys in development environments and live keys in production.\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Stripe** in your app settings.  \n2. Paste your **Stripe API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can process payments and manage billing directly from workflows and UI actions.\n\n## Step 3: Notes\n\n* **Keep your API key secure:** Never expose your Stripe key in client-side code.  \n* **Use environment-specific keys:** Test keys for staging, live keys for production.  \n* **Secure transactions:** All payment processing is handled through Stripe’s PCI-compliant infrastructure.  \n","frontmatter":{"description":"Connect your apps to Stripe to accept payments, manage subscriptions, and handle billing securely."},"isInternal":false,"tokens":380,"sizeBytes":1763},{"name":"supabase.md","path":"packages/integrations-docs/src/integrations_docs/docs/supabase.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/supabase.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: Data Infrastructure\ndescription: Connect your apps to Supabase to use a hosted Postgres database with real-time capabilities and powerful APIs.\n---\n# Supabase Integration\n\nThe **Supabase Integration** allows your app to connect to [Supabase](https://supabase.com/) — a hosted Postgres database with real-time subscriptions, authentication, and file storage. Once connected, your app can query and update data securely, power dashboards, and sync workflows in real time.\n\n## What You Can Do\n\nWith Supabase, your app can:\n- **Read and write data** using Postgres through a simple REST or client API.  \n- Enable **real-time updates** that sync automatically to your UI.  \n- Use **row-level security** and access control for safe data management.  \n- Store and retrieve files with Supabase Storage.  \n- Integrate seamlessly with AI, dashboards, or internal tools.\n\n## Step 1: Obtain Your Supabase URL and Key\n\n1. Go to your [Supabase Project](https://supabase.com/).\n2. Choose the project you want to connect.\n3. Navigate to **Project Settings**.\n4. Go to **Data API** and copy your `Supabase_URL`.\n5. Then go to **API Keys** and copy your `Supabase_Key` (the secret key).\n\n   * **Example URL:** `https://your-project.supabase.co`  \n   * **Example Key:** `sb_xxxxxxxxxxxxxxxxxxxxxxxxxxxx.`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Supabase** in your app settings.  \n2. Paste your **Supabase URL** and **Supabase Key** into the fields.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can query and update your Supabase database directly from workflows and UI actions.\n\n## Step 3: Notes\n\n* **Keep your keys secure:** Never expose the `Supabase_Key` key in client-side code.  \n* **Use environment-specific keys:** Separate dev, staging, and production projects for clean access control.  \n* **Realtime support:** Supabase enables live syncing of data changes.  \n* **Row-level security:** Make sure to configure policies appropriately for your use case.\n","frontmatter":{"tags":"Data Infrastructure","description":"Connect your apps to Supabase to use a hosted Postgres database with real-time capabilities and powerful APIs."},"isInternal":false,"tokens":490,"sizeBytes":2040},{"name":"twilio.md","path":"packages/integrations-docs/src/integrations_docs/docs/twilio.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/src/integrations_docs/docs/twilio.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"---\ntags: Communication\ndescription: Connect your apps to Twilio to send SMS, WhatsApp messages, and voice calls programmatically.\n---\n# Twilio Integration\n\nThe **Twilio Integration** allows your app to use [Twilio](https://www.twilio.com/) to send and receive SMS, WhatsApp messages, and voice calls. Once connected, your app can trigger messages or calls directly from workflows, user actions, or automated events.\n\n## What You Can Do\n\nWith Twilio, your app can:\n- **Send SMS** messages to users or customers globally.  \n- **Send and receive WhatsApp messages**.  \n- **Make and manage voice calls** programmatically.  \n- Automate **notifications**, **alerts**, and **transactional messages**.  \n- Integrate messaging into AI workflows for dynamic, real-time communication.\n\n## Step 1: Obtain Twilio Credentials\n\n1. Go to your [Twilio Console](https://www.twilio.com/console).  \n2. Copy your **Account SID** and **Auth Token** from the dashboard.  \n\n   * **Example Account SID:** `ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`  \n   * **Example Auth Token:** `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Twilio** in your app settings.  \n2. Paste your **Account SID** and **Auth Token** in the input fields.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can send messages or make calls through Twilio directly in workflows and components.\n\n## Step 3: Notes\n\n* **Keep your credentials secure:** Never expose your Auth Token in client-side code.  \n* **Use environment-specific credentials:** Separate dev, staging, and production credentials.  \n* **Phone number setup:** Ensure you’ve configured a valid Twilio number for sending messages or calls.  \n* **Regulatory compliance:** Review Twilio’s messaging and voice compliance requirements for your region.\n","frontmatter":{"tags":"Communication","description":"Connect your apps to Twilio to send SMS, WhatsApp messages, and voice calls programmatically."},"isInternal":false,"tokens":411,"sizeBytes":1861},{"name":"openapi.json","path":"packages/reflex-build-sdk/openapi.json","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-build-sdk/openapi.json","title":"Reflex-build-sdk Skill","category":"anthropic-skill","format":"json","content":"{\n  \"components\": {\n    \"schemas\": {\n      \"AccessJson\": {\n        \"description\": \"Serialized token access stored on the token row and in the AuthZ cache.\",\n        \"properties\": {\n          \"permissions\": {\n            \"additionalProperties\": {\n              \"type\": \"string\"\n            },\n            \"description\": \"Each permission the token holds, by key (`account`, `project`, `app`, `thread`), mapped to how much of it -- `none`, `read` or `write`.\",\n            \"title\": \"Permissions\",\n            \"type\": \"object\"\n          },\n          \"projects\": {\n            \"anyOf\": [\n              {\n                \"const\": \"all\",\n                \"type\": \"string\"\n              },\n              {\n                \"items\": {\n                  \"type\": \"string\"\n                },\n                \"type\": \"array\"\n              }\n            ],\n            \"description\": \"Which projects the project-scoped permissions above apply to: `all`, or the ids they are confined to.\",\n            \"title\": \"Projects\"\n          }\n        },\n        \"required\": [\n          \"permissions\",\n          \"projects\"\n        ],\n        \"title\": \"AccessJson\",\n        \"type\": \"object\"\n      },\n      \"AdminAppListEntry\": {\n        \"additionalProperties\": true,\n        \"description\": \"One row of the instance-admin app table.\\n\\nThe columns are fixed; what the request varies is the filter and the sort.\\nDeleted apps and projects are listed and flagged rather than hidden, since\\ntheir deployment rows outlive them and stay listed.\",\n        \"properties\": {\n          \"app_description\": {\n            \"description\": \"Free text the owner set.\",\n            \"title\": \"App Description\",\n            \"type\": \"string\"\n          },\n          \"app_id\": {\n            \"description\": \"The app's id.\",\n            \"format\": \"uuid\",\n            \"title\": \"App Id\",\n            \"type\": \"string\"\n          },\n          \"app_name\": {\n            \"description\": \"The app's name.\",\n            \"title\": \"App Name\",\n            \"type\": \"string\"\n          },\n          \"created_at\": {\n            \"description\": \"When the app row was created.\",\n            \"format\": \"date-time\",\n            \"title\": \"Created At\",\n            \"type\": \"string\"\n          },\n          \"deployment_count\": {\n            \"description\": \"Every deployment this app has ever had, on-prem rows included.\",\n            \"title\": \"Deployment Count\",\n            \"type\": \"integer\"\n          },\n          \"deployment_hostname\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The serving label it was given, nullable on the row and so absent independently of the deployment.\",\n            \"title\": \"Deployment Hostname\"\n          },\n          \"deployment_status\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"That deployment's status, null wherever `latest_deployment_id` is, as is `deployment_ts`. The two address fields between them are nullable on the deployment row itself, so either can be null while this is set.\",\n            \"title\": \"Deployment Status\"\n          },\n          \"deployment_ts\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"When that deployment's row was created, which a start or a rollback does not move.\",\n            \"title\": \"Deployment Ts\"\n          },\n          \"deployment_url\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The frontend a browser is pointed at. Null on a row whose serving host was never resolved -- a legacy row carries a bare `deployment_hostname` with no url -- so this is absent independently of the deployment.\",\n            \"title\": \"Deployment Url\"\n          },\n          \"full_deploy\": {\n            \"description\": \"Whether the whole app runs on the provider, frontend included, rather than serving its frontend from Reflex's CDN.\",\n            \"title\": \"Full Deploy\",\n            \"type\": \"boolean\"\n          },\n          \"is_deleted\": {\n            \"description\": \"Whether the app is soft-deleted.\",\n            \"title\": \"Is Deleted\",\n            \"type\": \"boolean\"\n          },\n          \"latest_deployment_id\": {\n            \"anyOf\": [\n              {\n                \"format\": \"uuid\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The app's current deployment -- a live or in-progress one before a terminal one, newest first, production identity only. Null for an app that has never deployed, and for one whose deployments are all on-prem, which this skips while `deployment_count` still counts them.\",\n            \"title\": \"Latest Deployment Id\"\n          },\n          \"org_id\": {\n            \"description\": \"The organization that owns the project.\",\n            \"format\": \"uuid\",\n            \"title\": \"Org Id\",\n            \"type\": \"string\"\n          },\n          \"org_name\": {\n            \"description\": \"That organization's name.\",\n            \"title\": \"Org Name\",\n            \"type\": \"string\"\n          },\n          \"project_id\": {\n            \"description\": \"The project the app is in.\",\n            \"format\": \"uuid\",\n            \"title\": \"Project Id\",\n            \"type\": \"string\"\n          },\n          \"project_is_deleted\": {\n            \"description\": \"Whether the project is soft-deleted. Deleting a project only queues its apps' own delete, so inside that window this is the app's only marker.\",\n            \"title\": \"Project Is Deleted\",\n            \"type\": \"boolean\"\n          },\n          \"project_name\": {\n            \"description\": \"That project's name.\",\n            \"title\": \"Project Name\",\n            \"type\": \"string\"\n          },\n          \"provider\": {\n            \"description\": \"Where the app deploys: Reflex's own hosting, or the org's cloud account.\",\n            \"title\": \"Provider\",\n            \"type\": \"string\"\n          },\n          \"vm_type_name\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Read from the machine rather than the deployment row: a size-scale rewrites the machines and leaves the row's own vmtype_id at the size it was deployed at.\",\n            \"title\": \"Vm Type Name\"\n          }\n        },\n        \"required\": [\n          \"app_id\",\n          \"app_name\",\n          \"app_description\",\n          \"provider\",\n          \"full_deploy\",\n          \"is_deleted\",\n          \"created_at\",\n          \"project_id\",\n          \"project_name\",\n          \"project_is_deleted\",\n          \"org_id\",\n          \"org_name\",\n          \"latest_deployment_id\",\n          \"deployment_status\",\n          \"deployment_url\",\n          \"deployment_hostname\",\n          \"deployment_ts\",\n          \"vm_type_name\",\n          \"deployment_count\"\n        ],\n        \"title\": \"AdminAppListEntry\",\n        \"type\": \"object\"\n      },\n      \"AdminAppMoveResponse\": {\n        \"description\": \"What the move did, in the shape the app route's own move answers.\\n\\nThe three repository fields come from ``move_shortfall_payload``, which both\\nmove paths share so they cannot come to spell a key differently -- a reader\\ntakes an absent key for a move that cost nothing. The destination is named\\n``target_project_id`` here and ``project_id`` there, which is the one\\ndifference and is what each has always answered with.\",\n        \"properties\": {\n          \"app_id\": {\n            \"description\": \"The app that moved.\",\n            \"format\": \"uuid\",\n            \"title\": \"App Id\",\n            \"type\": \"string\"\n          },\n          \"copied_integrations\": {\n            \"description\": \"The integrations copied across to the destination project.\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"title\": \"Copied Integrations\",\n            \"type\": \"array\"\n          },\n          \"message\": {\n            \"description\": \"What the move did, for a reader.\",\n            \"title\": \"Message\",\n            \"type\": \"string\"\n          },\n          \"permissions_repointed\": {\n            \"description\": \"Whether the app's authorization tuples were repointed at the destination project. False leaves who can reach the app answered by the *source* project until the periodic reconciler heals it -- the move landed, so this is reported rather than raised.\",\n            \"title\": \"Permissions Repointed\",\n            \"type\": \"boolean\"\n          },\n          \"repo_token_notices\": {\n            \"description\": \"The two lists above said in sentences, for showing somebody. Free text; read the lists to branch.\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"title\": \"Repo Token Notices\",\n            \"type\": \"array\"\n          },\n          \"repo_tokens_failed\": {\n            \"description\": \"Threads whose credential the hand-over could not write. The move landed, so these are reported rather than raised -- and nothing revisits them: those apps cannot push until somebody reconnects.\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"title\": \"Repo Tokens Failed\",\n            \"type\": \"array\"\n          },\n          \"repo_tokens_withheld\": {\n            \"description\": \"Threads whose repository credential was deliberately not handed over, because the destination is not entitled to it.\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"title\": \"Repo Tokens Withheld\",\n            \"type\": \"array\"\n          },\n          \"target_project_id\": {\n            \"description\": \"Where it moved to. Named `project_id` on the app route's own move, which is the one difference between the two shapes and is what each has always answered with.\",\n            \"format\": \"uuid\",\n            \"title\": \"Target Project Id\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"message\",\n          \"app_id\",\n          \"target_project_id\",\n          \"copied_integrations\",\n          \"repo_tokens_withheld\",\n          \"repo_tokens_failed\",\n          \"repo_token_notices\",\n          \"permissions_repointed\"\n        ],\n        \"title\": \"AdminAppMoveResponse\",\n        \"type\": \"object\"\n      },\n      \"AdminDeploymentListEntry\": {\n        \"additionalProperties\": true,\n        \"description\": \"One row of the instance-admin deployment table.\\n\\nFixed columns, for the reason the app table's are: the request varies the\\nfilter and the sort.\",\n        \"properties\": {\n          \"app_id\": {\n            \"description\": \"The app it belongs to.\",\n            \"format\": \"uuid\",\n            \"title\": \"App Id\",\n            \"type\": \"string\"\n          },\n          \"app_is_deleted\": {\n            \"description\": \"Whether the app is soft-deleted.\",\n            \"title\": \"App Is Deleted\",\n            \"type\": \"boolean\"\n          },\n          \"app_name\": {\n            \"description\": \"That app's name.\",\n            \"title\": \"App Name\",\n            \"type\": \"string\"\n          },\n          \"deployed_by_email\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"That account's address, where it still has one.\",\n            \"title\": \"Deployed By Email\"\n          },\n          \"deployed_by_id\": {\n            \"anyOf\": [\n              {\n                \"format\": \"uuid\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Who submitted it, null where that account has since been purged -- as are the two fields below it.\",\n            \"title\": \"Deployed By Id\"\n          },\n          \"deployed_by_username\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"And its display name, not a handle: derived from the address for a person, and the name an org admin chose for a service account.\",\n            \"title\": \"Deployed By Username\"\n          },\n          \"deployment_id\": {\n            \"description\": \"The deployment's id.\",\n            \"format\": \"uuid\",\n            \"title\": \"Deployment Id\",\n            \"type\": \"string\"\n          },\n          \"deployment_ts\": {\n            \"description\": \"When the row was created. Not when it went live: a start or a rollback re-parks a row that may be weeks old.\",\n            \"format\": \"date-time\",\n            \"title\": \"Deployment Ts\",\n            \"type\": \"string\"\n          },\n          \"description\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The submitter's changelog note for this deployment, not the app's own description.\",\n            \"title\": \"Description\"\n          },\n          \"hostname\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The serving label it was given.\",\n            \"title\": \"Hostname\"\n          },\n          \"persist\": {\n            \"description\": \"Exempt from idle suspension, so the app keeps a machine running with no traffic.\",\n            \"title\": \"Persist\",\n            \"type\": \"boolean\"\n          },\n          \"project_id\": {\n            \"description\": \"The project the app is in.\",\n            \"format\": \"uuid\",\n            \"title\": \"Project Id\",\n            \"type\": \"string\"\n          },\n          \"project_is_deleted\": {\n            \"description\": \"Deleting a project only queues its apps' soft-delete, so inside that window this is a row's only marker.\",\n            \"title\": \"Project Is Deleted\",\n            \"type\": \"boolean\"\n          },\n          \"python_version\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The Python version the build reported, which chose its base image.\",\n            \"title\": \"Python Version\"\n          },\n          \"reflex_version\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"What the app was built against, as the build reported it.\",\n            \"title\": \"Reflex Version\"\n          },\n          \"region_names\": {\n            \"description\": \"Where the deployment's machines are, empty if it has none.\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"title\": \"Region Names\",\n            \"type\": \"array\"\n          },\n          \"status\": {\n            \"description\": \"Where the deployment stands. This listing filters on nothing, so it carries every status the codebase writes: serving (`Running`, `Paused`, `Error: Out of Memory`), in flight (`Pending`, `AwaitingApproval`), never run (`Rejected`, `Superseded`, `Expired`) and finished (`Failed`, `Stopped`, `Historical`). The column is unconstrained text, so a legacy row can hold a value nothing writes any more -- `Removed` is the one still recognised, and an unlisted value is not a client error.\",\n            \"title\": \"Status\",\n            \"type\": \"string\"\n          },\n          \"strategy\": {\n            \"description\": \"How the rollout was made, as submitted: `immediate`, `rolling`, `bluegreen` or `canary`. `rolling` and `canary` are accepted on Fly only, and take the blue-green path.\",\n            \"title\": \"Strategy\",\n            \"type\": \"string\"\n          },\n          \"url\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"The frontend a browser is pointed at.\",\n            \"title\": \"Url\"\n          },\n          \"vm_type_cpu\": {\n            \"anyOf\": [\n              {\n                \"type\": \"number\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"That machine's CPU count.\",\n            \"title\": \"Vm Type Cpu\"\n          },\n          \"vm_type_name\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Read from the machine rather than the row: a size-scale rewrites the machines and leaves `vmtype_id` at the size the deployment was made at. Null where no machine answered.\",\n            \"title\": \"Vm Type Name\"\n          },\n          \"vm_type_ram\": {\n            \"anyOf\": [\n              {\n                \"type\": \"number\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"That machine's memory, in GB, as the catalog stores it -- a 4096 MB machine reads 4.096.\",\n            \"title\": \"Vm Type Ram\"\n          },\n          \"vmtype_id\": {\n            \"description\": \"The machine size the row was deployed at, as stored. `GET /deployments/vm_types` resolves a catalog size and not the `custom-c<cpu>m<ram_mb>` id an explicit cpu/memory deploy mints, nor on-prem's `prem`; the `vm_type_*` fields below carry the shape either way.\",\n            \"title\": \"Vmtype Id\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"deployment_id\",\n          \"app_id\",\n          \"app_name\",\n          \"app_is_deleted\",\n          \"project_id\",\n          \"project_is_deleted\",\n          \"status\",\n          \"url\",\n          \"hostname\",\n          \"deployment_ts\",\n          \"reflex_version\",\n          \"python_version\",\n          \"persist\",\n          \"strategy\",\n          \"description\",\n          \"vmtype_id\",\n          \"vm_type_name\",\n          \"vm_type_ram\",\n          \"vm_type_cpu\",\n          \"deployed_by_id\",\n          \"deployed_by_email\",\n          \"deployed_by_username\",\n          \"region_names\"\n        ],\n        \"title\": \"AdminDeploymentListEntry\",\n        \"type\": \"object\"\n      },\n      \"AppAudience\": {\n        \"description\": \"Who an app will sign in.\\n\\nOnly ``PUBLIC`` admits somebody with no standing at all, which is why it is\\nthe one mode a change *to* needs no session sweep: every other value can\\nonly take admission away from somebody who holds it now, and a mode that\\nrefuses the next sign-in while leaving the current one running is not the\\ncontrol it says it is.\\n\\n``MEMBERS`` and ``INVITED`` are not ordered against each other. An invited\\nstranger is not a member, and a member is not necessarily invited, so\\n\\\"narrower\\\" is not a total order here and nothing tries to make it one --\\nwhich is why the sweep asks what is being moved *to* rather than comparing\\nthe two.\",\n        \"enum\": [\n          \"public\",\n          \"members\",\n          \"invited\",\n          \"owner_only\"\n        ],\n        \"title\": \"AppAudience\",\n        \"type\": \"string\"\n      },\n      \"AppAudienceChangedResponse\": {\n        \"description\": \"An audience change, and the sessions the narrowing ended.\\n\\n``changed`` is false where the mode was already the one asked for.\\n``revoked_sessions`` is a count and ``sweep_failed`` says whether it ran,\\nfor the reason a block's are.\",\n        \"properties\": {\n          \"audience\": {\n            \"description\": \"The mode the app is on now.\",\n            \"title\": \"Audience\",\n            \"type\": \"string\"\n          },\n          \"changed\": {\n            \"description\": \"False where it was already the one asked for.\",\n            \"title\": \"Changed\",\n            \"type\": \"boolean\"\n          },\n          \"revoked_sessions\": {\n            \"description\": \"How many sessions the narrowing ended. Zero where the sweep failed as well as where there were none -- `sweep_failed` tells those apart, for the reason a block's does.\",\n            \"title\": \"Revoked Sessions\",\n            \"type\": \"integer\"\n          },\n          \"sweep_failed\": {\n            \"description\": \"Whether ending the sessions the new mode refuses is still owed, which is weaker than any being left running: the sweep is one bulk call, so a failure leaves how many there were unknown -- an app nobody was signed in to reports this too. The mode is committed before the sweep, so the change applied either way. Whatever was signed in ends at the next refresh, and setting the mode again sweeps them.\",\n            \"title\": \"Sweep Failed\",\n            \"type\": \"boolean\"\n          }\n        },\n        \"required\": [\n          \"audience\",\n          \"changed\",\n          \"revoked_sessions\",\n          \"sweep_failed\"\n        ],\n        \"title\": \"AppAudienceChangedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAudienceResponse\": {\n        \"description\": \"Who an app signs in, and -- for a caller entitled to it -- who is invited.\\n\\n``audience`` is null where the stored mode is one this deployment does not\\nknow -- which refuses every sign-in, so it is not ``public``.\\n\\n``invites`` is null rather than absent for a caller who may read the mode\\nand not the list, which is a set of email addresses. One shape with a\\nnullable field rather than two shapes, because a caller cannot discriminate\\na union whose members differ only by a key being missing: an empty list and\\na withheld list read identically, and \\\"there is nobody invited\\\" is the\\nopposite answer to \\\"you may not see who is\\\".\",\n        \"properties\": {\n          \"audience\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Who the app signs in. Null where the stored mode is one this deployment does not know -- which refuses every sign-in, so it is not `public`.\",\n            \"title\": \"Audience\"\n          },\n          \"invites\": {\n            \"anyOf\": [\n              {\n                \"items\": {\n                  \"$ref\": \"#/components/schemas/AppAuthInviteResponse\"\n                },\n                \"type\": \"array\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Who is invited, or null for a caller who may read the mode and not the list. Nullable rather than absent, because an empty list and a withheld one read identically -- and `there is nobody invited` is the opposite answer to `you may not see who is`.\",\n            \"title\": \"Invites\"\n          }\n        },\n        \"required\": [\n          \"audience\",\n          \"invites\"\n        ],\n        \"title\": \"AppAudienceResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthAbsentResponse\": {\n        \"description\": \"An app the broker does not sign users in for.\\n\\n``client_enabled`` is reported either way: the client row can outlive the\\nkeys, so a half-torn-down app is visible as one rather than as clean.\",\n        \"properties\": {\n          \"client_enabled\": {\n            \"description\": \"Whether the broker will complete a login for this app. Written separately from the keys, so an app carrying them with the client row disabled refuses every sign-in -- which is why this is reported either way rather than implied by `has_auth`.\",\n            \"title\": \"Client Enabled\",\n            \"type\": \"boolean\"\n          },\n          \"has_auth\": {\n            \"const\": false,\n            \"description\": \"Always false on this body; the configured answer is the other member of the union.\",\n            \"title\": \"Has Auth\",\n            \"type\": \"boolean\"\n          },\n          \"kind\": {\n            \"description\": \"Which sign-in this app has, which `has_auth` alone cannot say: `none` is an app that signs nobody in, `managed` is the broker's, and `connected` is the app's own identity provider -- so a client offered \\\"set up sign-in\\\" can tell an app with nothing from one whose provider has to be disconnected first.\",\n            \"enum\": [\n              \"none\",\n              \"managed\",\n              \"connected\"\n            ],\n            \"title\": \"Kind\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"has_auth\",\n          \"client_enabled\",\n          \"kind\"\n        ],\n        \"title\": \"AppAuthAbsentResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthConfiguredResponse\": {\n        \"description\": \"An app the broker signs users in for, and as whom.\\n\\n``has_auth`` is what the app's own environment holds and\\n``client_enabled`` whether the broker will complete a login for it; an app\\ncarrying the keys with no enabled client row refuses every sign-in.\",\n        \"properties\": {\n          \"client_enabled\": {\n            \"description\": \"Whether the broker will complete a login for this app. Written separately from the keys, so an app carrying them with the client row disabled refuses every sign-in -- which is why this is reported either way rather than implied by `has_auth`.\",\n            \"title\": \"Client Enabled\",\n            \"type\": \"boolean\"\n          },\n          \"client_id\": {\n            \"description\": \"The app's OAuth client id, which is the app's own id. It is also the audience its identity tokens carry, so one app's token fails another app's check.\",\n            \"title\": \"Client Id\",\n            \"type\": \"string\"\n          },\n          \"has_auth\": {\n            \"const\": true,\n            \"description\": \"Always true on this body. It says what the app's own environment holds, which `client_enabled` beside it does not.\",\n            \"title\": \"Has Auth\",\n            \"type\": \"boolean\"\n          },\n          \"issuer\": {\n            \"description\": \"The OIDC issuer the app's client validates against. One per deployment, shared by every app -- what separates them is the audience, which is the app's own id.\",\n            \"title\": \"Issuer\",\n            \"type\": \"string\"\n          },\n          \"kind\": {\n            \"description\": \"Which sign-in this app has, which `has_auth` alone cannot say: `none` is an app that signs nobody in, `managed` is the broker's, and `connected` is the app's own identity provider -- so a client offered \\\"set up sign-in\\\" can tell an app with nothing from one whose provider has to be disconnected first.\",\n            \"enum\": [\n              \"none\",\n              \"managed\",\n              \"connected\"\n            ],\n            \"title\": \"Kind\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"has_auth\",\n          \"issuer\",\n          \"client_id\",\n          \"client_enabled\",\n          \"kind\"\n        ],\n        \"title\": \"AppAuthConfiguredResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthDeprovisionedResponse\": {\n        \"description\": \"A deprovisioning. ``deleted`` is false where there was nothing to take.\\n\\n``kind`` is what the app holds now, and is what separates the two ways\\n``deleted`` is false: an app that had no sign-in at all reads ``none``, and\\none carrying its own identity provider reads ``connected`` -- which this\\nroute deliberately does not touch, so the remedy is to disconnect that\\nrather than to retry here.\",\n        \"properties\": {\n          \"deleted\": {\n            \"description\": \"Whether this call took anything. False two ways, which `kind` separates: an app that had no sign-in at all, and one carrying its own identity provider, which this route deliberately does not touch.\",\n            \"title\": \"Deleted\",\n            \"type\": \"boolean\"\n          },\n          \"kind\": {\n            \"description\": \"Which sign-in this app has, which `has_auth` alone cannot say: `none` is an app that signs nobody in, `managed` is the broker's, and `connected` is the app's own identity provider -- so a client offered \\\"set up sign-in\\\" can tell an app with nothing from one whose provider has to be disconnected first.\",\n            \"enum\": [\n              \"none\",\n              \"managed\",\n              \"connected\"\n            ],\n            \"title\": \"Kind\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"deleted\",\n          \"kind\"\n        ],\n        \"title\": \"AppAuthDeprovisionedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthInviteCreatedResponse\": {\n        \"description\": \"One invited address, and whether *this* request is what added it.\\n\\n``created`` does not belong on the listing entry: it is a fact about one\\nrequest, and a row in a list has no request to be about.\",\n        \"properties\": {\n          \"created\": {\n            \"description\": \"Whether this request added the address. False means it was already invited and nothing changed, which the 200 rather than 201 also says.\",\n            \"title\": \"Created\",\n            \"type\": \"boolean\"\n          },\n          \"created_at\": {\n            \"description\": \"When it was invited.\",\n            \"format\": \"date-time\",\n            \"title\": \"Created At\",\n            \"type\": \"string\"\n          },\n          \"email\": {\n            \"description\": \"The invited address, folded -- which is the form the list is keyed by.\",\n            \"title\": \"Email\",\n            \"type\": \"string\"\n          },\n          \"redeemed\": {\n            \"description\": \"The same fact as a flag, for a client that only needs the yes or no.\",\n            \"title\": \"Redeemed\",\n            \"type\": \"boolean\"\n          },\n          \"redeemed_at\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"When somebody first signed in on it; null while nobody has.\",\n            \"title\": \"Redeemed At\"\n          }\n        },\n        \"required\": [\n          \"email\",\n          \"created_at\",\n          \"redeemed_at\",\n          \"redeemed\",\n          \"created\"\n        ],\n        \"title\": \"AppAuthInviteCreatedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthInviteResponse\": {\n        \"description\": \"One invited address, and whether anybody has signed in on it.\",\n        \"properties\": {\n          \"created_at\": {\n            \"description\": \"When it was invited.\",\n            \"format\": \"date-time\",\n            \"title\": \"Created At\",\n            \"type\": \"string\"\n          },\n          \"email\": {\n            \"description\": \"The invited address, folded -- which is the form the list is keyed by.\",\n            \"title\": \"Email\",\n            \"type\": \"string\"\n          },\n          \"redeemed\": {\n            \"description\": \"The same fact as a flag, for a client that only needs the yes or no.\",\n            \"title\": \"Redeemed\",\n            \"type\": \"boolean\"\n          },\n          \"redeemed_at\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"When somebody first signed in on it; null while nobody has.\",\n            \"title\": \"Redeemed At\"\n          }\n        },\n        \"required\": [\n          \"email\",\n          \"created_at\",\n          \"redeemed_at\",\n          \"redeemed\"\n        ],\n        \"title\": \"AppAuthInviteResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthProvisionedResponse\": {\n        \"description\": \"A provisioning. ``created`` is false where it was already there.\\n\\nCarries ``client_enabled`` like the read does, and for its reason: the two\\nhalves are written separately, so a provision that wrote the keys and left\\nthe client row disabled would otherwise answer exactly as a working one.\",\n        \"properties\": {\n          \"client_enabled\": {\n            \"description\": \"Whether the broker will complete a login for this app. Written separately from the keys, so an app carrying them with the client row disabled refuses every sign-in -- which is why this is reported either way rather than implied by `has_auth`.\",\n            \"title\": \"Client Enabled\",\n            \"type\": \"boolean\"\n          },\n          \"client_id\": {\n            \"description\": \"The app's OAuth client id, which is the app's own id. It is also the audience its identity tokens carry, so one app's token fails another app's check.\",\n            \"title\": \"Client Id\",\n            \"type\": \"string\"\n          },\n          \"created\": {\n            \"description\": \"Whether this call provisioned it; false where it was already there.\",\n            \"title\": \"Created\",\n            \"type\": \"boolean\"\n          },\n          \"has_auth\": {\n            \"const\": true,\n            \"description\": \"Always true: the provisioning wrote the keys.\",\n            \"title\": \"Has Auth\",\n            \"type\": \"boolean\"\n          },\n          \"issuer\": {\n            \"description\": \"The OIDC issuer the app's client validates against. One per deployment, shared by every app -- what separates them is the audience, which is the app's own id.\",\n            \"title\": \"Issuer\",\n            \"type\": \"string\"\n          },\n          \"kind\": {\n            \"description\": \"Always `managed` here, since a provision that answered anything else would have refused. Carried so the three sign-in routes report one field rather than three shapes a client has to tell apart.\",\n            \"enum\": [\n              \"none\",\n              \"managed\",\n              \"connected\"\n            ],\n            \"title\": \"Kind\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"has_auth\",\n          \"issuer\",\n          \"client_id\",\n          \"created\",\n          \"client_enabled\",\n          \"kind\"\n        ],\n        \"title\": \"AppAuthProvisionedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthUninvitedResponse\": {\n        \"description\": \"An address taken off the invite list, and the sessions it held.\\n\\nThe address is echoed folded, which is the form the list is keyed by.\",\n        \"properties\": {\n          \"email\": {\n            \"description\": \"The address taken off the list, echoed folded.\",\n            \"title\": \"Email\",\n            \"type\": \"string\"\n          },\n          \"revoked_sessions\": {\n            \"description\": \"How many sessions the withdrawn invite had admitted. Zero where the sweep failed, where the route could not work out whose sessions to end -- the address is resolved to an account after the delete commits -- and where there were none. `sweep_failed` covers the first two; `withdrawn` says whether there was a row to take.\",\n            \"title\": \"Revoked Sessions\",\n            \"type\": \"integer\"\n          },\n          \"sweep_failed\": {\n            \"description\": \"Whether ending that address's sessions is still owed, which is weaker than one still running: the flag is set by a failure to resolve the address at all, and it may hold no account or be admitted by the app whatever the list says. The row is deleted before any of it, so the withdrawal applied either way -- ``withdrawn`` says whether there was one to take.\",\n            \"title\": \"Sweep Failed\",\n            \"type\": \"boolean\"\n          },\n          \"withdrawn\": {\n            \"description\": \"Whether there was an invite to take. The route is idempotent, so withdrawing one that is not there is a success -- this is what separates that from a withdrawal that removed something, which the session count cannot: an address nobody invited can still be holding a session a peer's withdrawal left behind, and one that was on the list can be holding none.\",\n            \"title\": \"Withdrawn\",\n            \"type\": \"boolean\"\n          }\n        },\n        \"required\": [\n          \"email\",\n          \"revoked_sessions\",\n          \"sweep_failed\",\n          \"withdrawn\"\n        ],\n        \"title\": \"AppAuthUninvitedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthUserBlockedResponse\": {\n        \"description\": \"A block or unblock, in its two halves.\\n\\n``revoked_sessions`` counts what the sweep ended; ``sweep_failed`` is what\\nsays whether it ran. A sweep that failed reports zero and sets the flag,\\nrather than a null the flag beside it already says more about.\",\n        \"properties\": {\n          \"blocked\": {\n            \"description\": \"Where they stand now. On a 2xx this is what was asked for: an unblock that left them blocked -- because the sweep failed, or because a newer block stands -- is refused rather than answered here.\",\n            \"title\": \"Blocked\",\n            \"type\": \"boolean\"\n          },\n          \"blocked_at\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"When the block was made; null once it is lifted.\",\n            \"title\": \"Blocked At\"\n          },\n          \"revoked_sessions\": {\n            \"description\": \"How many live sessions were ended. Zero where the sweep failed as well as where there were none to end -- `sweep_failed` is what tells those apart, and it is the field to read.\",\n            \"title\": \"Revoked Sessions\",\n            \"type\": \"integer\"\n          },\n          \"sweep_failed\": {\n            \"description\": \"Whether ending this person's live sessions is still owed. Only a **block** can answer true here: it is written before the sweep, so it applied and how many sessions outlive it is unknown -- the sweep is one bulk call, so a person who was holding none reports this too. An **unblock** lifts the flag after, so a failed sweep deliberately leaves them blocked and changes nothing -- which is a 503 rather than a success, since there is no sense in which the request applied.\",\n            \"title\": \"Sweep Failed\",\n            \"type\": \"boolean\"\n          },\n          \"user_id\": {\n            \"description\": \"The subject the block is about.\",\n            \"title\": \"User Id\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"user_id\",\n          \"blocked\",\n          \"blocked_at\",\n          \"revoked_sessions\",\n          \"sweep_failed\"\n        ],\n        \"title\": \"AppAuthUserBlockedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthUserListResponse\": {\n        \"description\": \"A page of an app's users, and how many people there are in all.\\n\\n``search`` is echoed stripped, which is the term the page was filtered on.\",\n        \"properties\": {\n          \"limit\": {\n            \"description\": \"How many rows this page holds at most.\",\n            \"title\": \"Limit\",\n            \"type\": \"integer\"\n          },\n          \"offset\": {\n            \"description\": \"Where it started.\",\n            \"title\": \"Offset\",\n            \"type\": \"integer\"\n          },\n          \"search\": {\n            \"description\": \"The term the page was filtered on, echoed stripped -- which is the form it was applied in.\",\n            \"title\": \"Search\",\n            \"type\": \"string\"\n          },\n          \"total\": {\n            \"description\": \"How many match in all, so a client can page without walking to the end.\",\n            \"title\": \"Total\",\n            \"type\": \"integer\"\n          },\n          \"users\": {\n            \"description\": \"This page of the app's users.\",\n            \"items\": {\n              \"$ref\": \"#/components/schemas/AppAuthUserResponse\"\n            },\n            \"title\": \"Users\",\n            \"type\": \"array\"\n          }\n        },\n        \"required\": [\n          \"users\",\n          \"total\",\n          \"limit\",\n          \"offset\",\n          \"search\"\n        ],\n        \"title\": \"AppAuthUserListResponse\",\n        \"type\": \"object\"\n      },\n      \"AppAuthUserResponse\": {\n        \"description\": \"One person an app has signed in.\\n\\nEach timestamp is named for the fact it holds: an agreement is not a\\nsign-in, and neither is a token refresh. ``last_active_at`` is null once\\nevery grant is gone rather than filled in from the consent beside it.\",\n        \"properties\": {\n          \"blocked\": {\n            \"description\": \"Whether the app refuses them a new sign-in. It does not end a session already running -- revoking their grants is what does that.\",\n            \"title\": \"Blocked\",\n            \"type\": \"boolean\"\n          },\n          \"blocked_at\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"When the app blocked them; null for somebody it has not.\",\n            \"title\": \"Blocked At\"\n          },\n          \"consented_at\": {\n            \"description\": \"Their last agreement. A sign-in that asked for nothing new leaves it alone, so it is when they last chose rather than when they were last here.\",\n            \"format\": \"date-time\",\n            \"title\": \"Consented At\",\n            \"type\": \"string\"\n          },\n          \"email\": {\n            \"description\": \"Withheld where the scope was: an app granted neither sees an opaque subject, so its owner is shown the same.\",\n            \"title\": \"Email\",\n            \"type\": \"string\"\n          },\n          \"first_consented_at\": {\n            \"description\": \"When they first agreed to sign in here, which is what created the row. Not a first sign-in: the code that consent minted can go unredeemed. It is the one instant that never moves, which is what the export pages on.\",\n            \"format\": \"date-time\",\n            \"title\": \"First Consented At\",\n            \"type\": \"string\"\n          },\n          \"last_active_at\": {\n            \"anyOf\": [\n              {\n                \"format\": \"date-time\",\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Their newest grant, which is as often a token renewal as a login -- deliberately not called a sign-in, since the row that *was* one goes with the prune. Null once every grant is gone rather than filled in from the consent beside it.\",\n            \"title\": \"Last Active At\"\n          },\n          \"name\": {\n            \"anyOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"null\"\n              }\n            ],\n            \"description\": \"Withheld the same way as the address where the app was granted no profile scope.\",\n            \"title\": \"Name\"\n          },\n          \"user_id\": {\n            \"description\": \"The subject the app knows this person by: their platform account id, which is what the app's own code receives as `sub`.\",\n            \"title\": \"User Id\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"user_id\",\n          \"email\",\n          \"name\",\n          \"first_consented_at\",\n          \"last_active_at\",\n          \"consented_at\",\n          \"blocked_at\",\n          \"blocked\"\n        ],\n        \"title\": \"AppAuthUserResponse\",\n        \"type\": \"object\"\n      },\n      \"AppDatabaseAbsentResponse\": {\n        \"description\": \"An app with no managed database.\",\n        \"properties\": {\n          \"has_database\": {\n            \"const\": false,\n            \"description\": \"Always false on this body; the provisioned answer is the other member of the union.\",\n            \"title\": \"Has Database\",\n            \"type\": \"boolean\"\n          }\n        },\n        \"required\": [\n          \"has_database\"\n        ],\n        \"title\": \"AppDatabaseAbsentResponse\",\n        \"type\": \"object\"\n      },\n      \"AppDatabaseProvisionedResponse\": {\n        \"description\": \"A provisioning. ``created`` is false where one was already there.\",\n        \"properties\": {\n          \"created\": {\n            \"description\": \"Whether this call provisioned the database; false where one was already there and this answered with it.\",\n            \"title\": \"Created\",\n            \"type\": \"boolean\"\n          },\n          \"created_at\": {\n            \"description\": \"When it was provisioned.\",\n            \"title\": \"Created At\",\n            \"type\": \"string\"\n          },\n          \"database\": {\n            \"description\": \"The database name to connect to.\",\n            \"title\": \"Database\",\n            \"type\": \"string\"\n          },\n          \"has_database\": {\n            \"const\": true,\n            \"description\": \"Always true on this body; the no-database answer is the other member of the union, which carries it false.\",\n            \"title\": \"Has Database\",\n            \"type\": \"boolean\"\n          },\n          \"has_dev_branch\": {\n            \"description\": \"Whether a dev branch stands beside production, which is what a reset wipes. Without one a reset is refused unless the caller opts in by name, since the fallback would drop the deployed database.\",\n            \"title\": \"Has Dev Branch\",\n            \"type\": \"boolean\"\n          },\n          \"masked_connection_string\": {\n            \"description\": \"The connection string with its password removed. The real one is written into the app's own environment and is not served here.\",\n            \"title\": \"Masked Connection String\",\n            \"type\": \"string\"\n          },\n          \"project_id\": {\n            \"description\": \"The managed database project's id at the provider. Not the app id, which is only what the project is named after -- address the provider with this one.\",\n            \"title\": \"Project Id\",\n            \"type\": \"string\"\n          },\n          \"region\": {\n            \"description\": \"Where the database is provisioned.\",\n            \"title\": \"Region\",\n            \"type\": \"string\"\n          },\n          \"role\": {\n            \"description\": \"The role the connection string authenticates as.\",\n            \"title\": \"Role\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"has_database\",\n          \"project_id\",\n          \"region\",\n          \"created_at\",\n          \"database\",\n          \"role\",\n          \"masked_connection_string\",\n          \"has_dev_branch\",\n          \"created\"\n        ],\n        \"title\": \"AppDatabaseProvisionedResponse\",\n        \"type\": \"object\"\n      },\n      \"AppDatabaseResponse\": {\n        \"description\": \"An app's managed database, with the connection string masked.\\n\\n``has_dev_branch`` is what a reset would wipe: without a dev branch,\\n``POST /database/reset`` drops the deployed database instead.\",\n        \"properties\": {\n          \"created_at\": {\n            \"description\": \"When it was provisioned.\",\n            \"title\": \"Created At\",\n            \"type\": \"string\"\n          },\n          \"database\": {\n            \"description\": \"The database name to connect to.\",\n            \"title\": \"Database\",\n            \"type\": \"string\"\n          },\n          \"has_database\": {\n            \"const\": true,\n            \"description\": \"Always true on this body; the no-database answer is the other member of the union, which carries it false.\",\n            \"title\": \"Has Database\",\n            \"type\": \"boolean\"\n          },\n          \"has_dev_branch\": {\n            \"description\": \"Whether a dev branch stands beside production, which is what a reset wipes. Without one a reset is refused unless the caller opts in by name, since the fallback would drop the deployed database.\",\n            \"title\": \"Has Dev Branch\",\n            \"type\": \"boolean\"\n          },\n          \"masked_connection_string\": {\n            \"description\": \"The connection string with its password removed. The real one is written into the app's own environment and is not served here.\",\n            \"title\": \"Masked Connection String\",\n            \"type\": \"string\"\n          },\n          \"project_id\": {\n            \"description\": \"The managed database project's id at the provider. Not the app id, which is only what the project is named after -- address the provider with this one.\",\n            \"title\": \"Project Id\",\n            \"type\": \"string\"\n          },\n          \"region\": {\n            \"description\": \"Where the database is provisioned.\",\n            \"title\": \"Region\",\n            \"type\": \"string\"\n          },\n          \"role\": {\n            \"description\": \"The role the connection string authenticates as.\",\n            \"title\": \"Role\",\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"has_database\",\n          \"project_id\",\n          \"region\",\n          \"created_at\",\n          \"database\",\n          \"role\",\n          \"masked_connection_string\",\n          \"has_dev_branch\"\n        ],\n        \"title\": \"AppDatabaseResponse\",\n        \"type\": \"object\"\n      },\n      \"AppFullDeployParams\": {\n        \"description\": \"Params for flipping only an app's full-deploy hosting mode.\",\n        \"properties\": {\n          \"full_deploy\": {\n            \"description\": \"Whether to bundle the frontend into the provider container and serve it beside the backend. GCP-only and Enterprise-only: true on an app hosted anywhere else is refused rather than ignored. Flipping a live app stops it, so the next redeploy comes up in the new mode.\",\n            \"title\": \"Full Deploy\",\n            \"type\": \"boolean\"\n          }\n        },\n        \"required\": [\n          \"full_deploy\"\n        ],\n        \"title\": \"AppFullDeployParams\",\n        \"type\": \"object\"\n      },\n      \"AppFullDeployResponse\": {\n        \"description\": \"An app's hosting mode after a flip.\\n\\nFlipping a live app stops it first, and ``stop_confirmed`` reports whether\\nthat whole teardown settled -- which is weaker than a confirmed destroy.\\nTrue where nothing was live.\",\n        \"properties\": {\n          \"full_deploy\": {\n            \"description\": \"The h\n\n<!-- [TRUNCATED AT 50KB] -->","isInternal":false,"tokens":10682,"sizeBytes":50030},{"name":"README.md","path":"packages/hatch-reflex-pyi/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/hatch-reflex-pyi/README.md","title":"hatch-reflex-pyi Documentation","category":"plugin-manifest","format":"markdown","content":"# hatch-reflex-pyi\n\nHatch build hook that generates .pyi stubs for Reflex component packages.\n","isInternal":false,"tokens":23,"sizeBytes":94},{"name":"README.md","path":"packages/integrations-docs/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/integrations-docs/README.md","title":"integrations-docs Documentation","category":"plugin-manifest","format":"markdown","content":"# reflex-integrations-docs\n\nReflex Integrations Docs.\n","isInternal":false,"tokens":14,"sizeBytes":54},{"name":"README.md","path":"packages/reflex-base/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-base/README.md","title":"reflex-base Documentation","category":"plugin-manifest","format":"markdown","content":"# reflex-base\n\nCore types for the Reflex framework.\n","isInternal":false,"tokens":11,"sizeBytes":52},{"name":"README.md","path":"packages/reflex-bench/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-bench/README.md","title":"reflex-bench Documentation","category":"plugin-manifest","format":"markdown","content":"# reflex-bench\n\nMacro benchmarks for Reflex. `reflex-bench` drives benchmarks through one command\nline interface, stores every raw sample with the machine it ran on, and compares\nresults with statistics that say \"inconclusive\" instead of guessing.\n\nThe CLI is the only code path: CI runs the same commands and only adds output\ntargets. The harness never imports the reflex under test; benchmarks reach it\nthrough subprocesses, HTTP, sockets and a browser. This package is used inside\nthis repository only and is never published.\n\n```console\n$ uv run reflex-bench list --suite selftest\n$ uv run reflex-bench run --suite selftest\n$ uv run reflex-bench run selftest.noise --param shift=1.2 --baseline 0001\n$ uv run reflex-bench run --reflex 0.8.23 --suite selftest\n$ uv run reflex-bench ab --base git:main --head workspace --suite selftest\n$ uv run reflex-bench compare base.json head.json --format md\n$ uv run reflex-bench doctor\n$ uv run reflex-bench export result.json --to bmf\n$ uv run reflex-bench budgets check result.json\n$ uv run reflex-bench noise ../bench-data/runs/<profile_id> --format md\n$ uv run reflex-bench subjects list\n```\n\n## Commands\n\n| Command | What it does |\n| --- | --- |\n| `list [FILTER...] [--suite NAME]` | Benchmarks with their parameters, kind, metrics, suites and estimated duration. |\n| `run [FILTER...] [--reflex SPEC]` | Runs benchmarks against one reflex, prints the result table, autosaves the result and optionally compares it with a baseline. |\n| `ab --base SPEC --head SPEC [FILTER...]` | Measures two reflexes in alternation on this machine and compares them ([A/B runs](#ab-runs)). |\n| `show FILE [--samples]` | One result in detail, optionally with every raw sample. |\n| `compare BASE HEAD [--format term\\|md\\|json]` | Compares two results; `json` prints the annotated head result. |\n| `doctor` | Machine checks that affect measurement noise, with fix hints. |\n| `export FILE --to md\\|bmf [-o OUT]` | Pull request markdown or [Bencher Metric Format](https://bencher.dev/docs/reference/bencher-metric-format/). |\n| `budgets check FILE [--budgets BUDGETS]` | Checks a result against the metric maxima of `budgets.json` ([Size budgets](#size-budgets)). |\n| `noise PATH... [--kind daily] [--min-runs 10] [--format term\\|md\\|json]` | The per-metric noise table of stored results ([Noise table](#noise-table)). |\n| `subjects list` | The cached [subject](#subjects) venvs: spec, Python, key, size and last use. |\n| `subjects prune [--older-than 30d]` | Deletes venvs not used for that long (`30d`, `12h`, `90m`), leftovers of interrupted builds and git worktrees no venv uses. |\n\n`FILTER` is a glob on the benchmark id (`lifecycle.*`, `*.warm`). Suites are named\nselections: `smoke`, `pr`, `daily`, `macro` (the timings the CodSpeed macro\nrunner measures, see [CI](#ci)), `selftest` and `all` (every benchmark except\nthe self-tests). Self-tests only run when asked for, with `--suite selftest` or a\nfilter starting with `selftest`.\n\nMain `run` options (every effective value is printed in the header and stored in\nthe result's `policy` block):\n\n| Option | Default | |\n| --- | --- | --- |\n| `--reflex SPEC` | `workspace` | The reflex to measure (see [Subjects](#subjects)). |\n| `--python VERSION` | the harness's | The Python of subject venvs (major.minor of the interpreter running reflex-bench, which the workspace runs on). |\n| `--runs N` | automatic | Fixed number of timed runs. |\n| `--min-runs`, `--max-runs`, `--min-time` | 10, max(30, min-runs), 30 s | The automatic run count (below). |\n| `--warmup N` | per benchmark | Untimed runs, stored but excluded from statistics. |\n| `--timeout SECONDS` | per benchmark | Deadline of each `prepare`, `sample` and `conclude` call. |\n| `--param KEY=VALUE` | | Restricts a parameter to one value, or sets a new value or a hidden parameter. |\n| `--baseline NAME\\|FILE\\|NUMBER` | | Compares with a file, a named baseline or an autosave number (`0041`). |\n| `--save/--no-save`, `--save-as NAME`, `--json FILE` | autosave | Where to store the result. |\n| `--threshold PCT`, `--alpha FLOAT` | 3, 0.01 | Practical threshold and significance level of verdicts. |\n| `--fail-on regression\\|never`, `--fail-on-inconclusive` | never locally, regression when `CI=true` | Exit codes 2 and 3. |\n| `--smoke` | | One run, no warmup, no statistics: checks that each benchmark works. |\n| `--ndjson` | | Progress events as JSON lines on stdout; human output moves to stderr. |\n| `--seed INT` | random | Seeds each benchmark's RNG and the bootstrap; always recorded. |\n| `--keep` | | Keeps each benchmark's work directory. |\n| `--kind` | `local` or `ci` | The run kind recorded in the result (`pr`, `daily`, `backfill`, `aa`). |\n\nExit codes: `0` ok, `1` harness error (including usage errors and every benchmark\nfailing), `2` regression with `--fail-on regression`, `3` inconclusive result\nwith `--fail-on-inconclusive`, `4` nothing to compare (no metric has samples on\nboth sides with matching series keys, and no benchmark started failing). A\nbenchmark that fails or times out is reported with its status and does not stop\nthe run; when comparing, one that fails or times out in head but not in base (or\nis new) is a regression.\nCtrl-C during `run` exits with `130` after saving the benchmarks that finished,\nmarked with `\"interrupted\": true`; the benchmark in progress is left out, and `--save-as` keeps the old baseline.\n\nWith `CI=true` the output is plain (no colors, no live progress, one line per\nfinished benchmark) and `--fail-on` defaults to `regression`. Nothing else changes.\n\n## Subjects\n\nThe reflex under test, `--reflex SPEC` (`--base` and `--head` for `ab`):\n\n| SPEC | Meaning |\n| --- | --- |\n| `workspace` (default) | This checkout, in the harness's own environment. |\n| `0.8.23`, any PEP 440 version | `reflex==<version>` from PyPI. |\n| `git:<ref>` | A commit, branch or tag of the current repository, e.g. `git:main`, `git:v0.9.11`. |\n| `path:<dir>` | Another local checkout, e.g. `path:../reflex-wt-other`. |\n\nEvery spec but `workspace` runs in its own virtualenv, `<home>/venvs/<key>/`,\ncreated with `uv venv --relocatable --python <--python>` and never containing\nthe harness. The key is the first 16 hex digits of the SHA-256 of the subject's\nidentity (the version; the commit of a git ref; the absolute path, commit and\ndirty flag of a path), the `--python` value and the harness's extra subject\nrequirements (`SUBJECT_REQUIREMENTS`: `sqlmodel` and `alembic`, the ranges of reflex's `db` extra, for the playground's database, and `plotly`, which `rx.plotly` imports). A venv is built in a temporary directory and renamed\ninto place when complete, under a lock, so a half-built venv is never reused and\nconcurrent runs build it once. A `path:` subject with uncommitted changes (or\noutside git) is rebuilt every time. The build happens before anything is timed\nand says what it does (`building venv for reflex 0.8.23 (py3.12)…`, `reusing\nvenv …`).\n\nA `git:` subject is checked out as a detached git worktree in\n`<home>/src/<commit>/` (reused when present; a worktree keeps the tags the\npackages' versions are computed from). A checkout with a `uv.lock` is installed\nwith the dependency set of `uv export --frozen --no-dev --package reflex`,\nwhich lists `reflex` and every workspace package it needs (`reflex-base`,\n`reflex-components-*`, ...) as editable paths in the checkout, so the\ndevelopment versions reflex pins never come from PyPI; the other dependencies\nare the locked ones, and the exported list is kept in the venv as\n`reflex-bench-requirements.txt`. A checkout without a lock (older than uv) is\ninstalled directly, editable.\n\nThe subject records its interpreter, `reflex_version`, `python_version` and\n`extra.granian`, all read by running the subject's interpreter on package\nmetadata (the harness never imports reflex), plus `commit` and `dirty` for git\nand path subjects. Benchmarks get the subject's interpreter directory first on\n`PATH` in `ctx.env`, so commands reflex starts by name (reflex 0.8 starts\n`granian` in production mode) come from the subject's venv.\n`subjects list` and `subjects prune` manage the cached venvs.\n\n## Writing a benchmark\n\nBenchmarks live in modules of `reflex_bench.suites`; every module there is\nimported on discovery.\n\n```python\nimport time\n\nfrom reflex_bench.registry import Metric, benchmark\n\n\n@benchmark(\n    id=\"selftest.sleep\",\n    suites=(\"selftest\",),\n    kind=\"time\",  # time | startup | rate | latency | peakmem | track\n    params={\"ms\": [10, 50]},  # cartesian product: selftest.sleep[ms=10], [ms=50]\n    metrics={\"wall\": Metric(unit=\"s\", direction=\"lower\")},\n    warmup=1,\n    timeout=60,  # seconds per prepare/sample/conclude call\n    estimate=5,  # rough seconds per sample, for `list`\n    min_version=None,  # e.g. \"0.9.8\": older subjects report \"unsupported\"\n)\nclass Sleep:\n    \"\"\"Sleep for a fixed time; checks the timing pipeline.\"\"\"\n\n    def setup_cache(self, ctx): ...  # once per subject and parameter set\n    def setup(self, ctx): ...  # once per instance\n    def prepare(self, ctx): ...  # before each sample, untimed\n    def sample(self, ctx):  # one sample\n        time.sleep(ctx.params[\"ms\"] / 1000)\n\n    def conclude(self, ctx): ...  # after each sample, untimed\n    def cleanup(self, ctx): ...  # once at the end\n```\n\nEvery hook except `sample` is optional; `conclude` and `cleanup` always run, also\nafter a failure or a timeout. Further `@benchmark` arguments:\n`hidden_params={\"name\": default}` for parameters that are passed to hooks but are\nnot part of the name or the series key, `suite_params={\"smoke\": {\"sessions\":\n[10]}}` for the values a parameter takes when that suite is selected (a quick\nsubset of the grid; `--param` still wins), and `setup_timeout` (600 s) for\n`setup_cache`, `setup` and `cleanup`.\n\n**Metrics** are declared with `Metric(unit, direction, assume=\"nothing\",\ndescription=\"\")`. Values are stored in SI base units (`s`, `B`, `ev/s`, `1` for\ncounts); scaling to ms or MB only happens on display. `assume=\"exact\"` marks a\ndeterministic value: one run is enough and any variance is reported.\n\n**`sample(ctx)`** returns `None`, a dict of metric values, or\n`SampleResult(values, extra)` whose JSON-serializable `extra` is stored with the\nsample. The harness always times the call; a declared `wall` metric that\n`sample()` does not return is filled with that duration. Returning an undeclared\nmetric, or leaving out a declared one, fails the benchmark.\n\n**`ctx`** is a `reflex_bench.context.Context`: `subject` (the reflex under test:\n`python`, `reflex_version`, `commit`, `dirty`, ...), `params` (hidden ones\nincluded), `workdir` (fresh per instance, removed after `cleanup` unless\n`--keep`), `cache_dir` (persistent per subject commit, benchmark id and\nparameter set, for `setup_cache` results; the hook decides what to reuse),\n`env` (the environment for subprocesses: telemetry and update checks off,\n`NO_COLOR`, `PYTHONUNBUFFERED`, `PYTHONHASHSEED=0`, granian, the subject's\ninterpreter directory first on `PATH`), `rng` (seeded), `log`, `arm` and\n`dims`: `setup` may name how the values are measured there, e.g.\n`ctx.dims[\"memory_method\"] = \"cgroup\"`, and the scheduler copies it into the\nentry's `dims`, which are part of the series key, so differently measured\nvalues never pair up in a comparison.\n\nAll hooks of an instance run on one worker thread, so thread-bound resources\n(such as a sync Playwright browser) work across hooks. A hook that misses its\ndeadline ends the instance with status `timeout`; the stuck thread is abandoned\nand the remaining teardown hooks run on a fresh one (as they do after Ctrl-C),\nso `conclude` should kill whatever `sample` started. A hook still running a few\nseconds after teardown keeps the work directory and skips the benchmark's\nremaining parameter sets. `reflex_bench.registry.Instance` exposes the hooks as\nzero-argument methods and `reflex_bench.scheduler.make_context` builds the same\ncontext as the scheduler, for callers other than the scheduler.\n\n**Keep heavy processes per sample.** During [`ab`](#ab-runs) both arms'\nsessions are open at the same time, `setup` to `cleanup`. A benchmark that\nkeeps a heavy process (a server) alive between samples runs two of them at\nonce, which distorts both arms. Start per-sample processes in `prepare` or\n`sample` and stop them in `conclude`. This is not enforced. Two kinds of\nbenchmarks keep one server per instance on purpose, and say why in their\ndocstrings: `browser.prod.pageload` (a prod start includes a full frontend\nbuild, and an idle second server does not touch page load) and the `hmr.*`\nbenchmarks (a dev start plus hydration before every edit would multiply their\nrun time by about ten, and the other arm's server only idles while this one\nrecompiles).\n\n## Driving reflex\n\nBenchmarks start the reflex under test as a user does, `<python> -m reflex ...`\nwith the subject's interpreter, through `reflex_bench.drivers.app_process`:\n\n```python\nfrom reflex_bench.collectors.cgroup import CgroupScope\nfrom reflex_bench.drivers.app_process import AppProcess, cache_env, run_cli\n\nenv = {**ctx.env, **cache_env(reflex_dir=ctx.cache_dir / \"reflex\")}\nscope = CgroupScope() if CgroupScope.available() is None else None\nresult = run_cli(\n    ctx.subject.python,\n    [\"compile\"],\n    cwd=app,\n    env=env,\n    timeout=600,\n    scope=scope,\n    phases=True,\n    sample_memory=scope is None,\n).check()  # wall_s, cpu_s, peak_mem_bytes, timing, attribution()\n\nself.app = AppProcess(\n    ctx.subject.python,\n    app,\n    mode=\"prod\",\n    reflex_version=ctx.subject.reflex_version,\n    env=env,\n)\nreadiness = self.app.start()  # process-ready: ready lines + every port accepts TCP\nself.app.wait_http_ready()  # GET / (or /ping without a frontend) answers 200\n# conclude(): self.app.stop() kills the whole process tree\n```\n\nThe driver picks free ports, expects the ready lines of the subject's version\nand mode (0.8.23 prod runs sirv and the backend on two ports, 0.9 prod one\nport) and never trusts a line without a TCP probe. It runs with the `env` it\nis given: pass `ctx.env`, or `reflex_bench.context.subject_env(python)` outside\na benchmark, so the subject's commands come first on `PATH`. Each command runs in its own session; `stop()` and the end of\n`run_cli` kill the whole tree, children that started their own session\nincluded. Peak memory and CPU come from a transient cgroup v2 scope when\n`systemd-run` works (user manager, or sudo on CI), else from PSS sampling\n(`memory_method: pss_sampling`, never compared with cgroup peaks);\n`reflex-bench doctor` shows which. With `phases=True`, `attribution()` splits\nthe command's wall and CPU time between three classes of processes sampled\nfrom its tree: `install` (`bun`/`npm`/`pnpm`/`yarn` `install`/`add` and what\nthey start), `frontend` (`node`, `vite`, `react-router`, `esbuild` and what\nthey start) and `python`, the interpreter and everything else. A tool's wall\nis the time it was alive; python's is the total minus the time any tool was\nalive, when the interpreter only waits. `cpu` per class is checked against\nthe measured total (`mismatch` beyond 10 %), `idle` is wall time not spent on\nCPU, and `python_breakdown` keeps the `[timing]` phases of the compile.\n`selftest.app.compile` and `selftest.app.dev_ready` exercise all of it against\na blank app.\n`run_cli(..., prefix=(\"-c\", \"import reflex\"))` runs other interpreter\narguments than `-m reflex` through the same process tree code.\n\n## Fixtures\n\nA fixture is the app a benchmark drives, described by a `FixtureDoc` (`name`,\n`content_hash`, `params`). A benchmark sets `ctx.fixture` in `setup_cache` or\n`setup`, and its entry records the name in `dims` (`{\"fixture\": \"playground\"}`,\npart of the pairing and series keys) and the hash in `fixture_hash` (part of\nthe series key only): an edited fixture pairs with its old self and `compare`\nreports the pair as not comparable, `fixture content hash differs`, unless\n`--force`. Hooks record anything else that separates series in `ctx.dims`.\nOne invocation drives several fixtures, so the document-level `fixture` stays\n`null`.\n\n- **The playground**, `examples/playground`: a committed app whose hash is the\n  line in its `.content-hash` (see its README for the element ids and hot reload\n  targets benchmarks rely on). `materialize_playground(dest)` copies it without\n  build output. It has 21 pages (about 3000 component instances, 16 states)\n  and a sqlite table: loading the app seeds 2000 fixed rows into an empty table,\n  in one transaction, so each staged copy creates its `playground.db` once. It\n  needs `sqlmodel`, `alembic` and `plotly`, which\n  `SUBJECT_REQUIREMENTS` installs into subject venvs; the workspace gets them\n  from the `dev` group.\n- **Generated apps**, `reflex_bench.fixtures.generate`: `GenParams(pages,\n  components_per_page, state_vars, substate_depth, computed_vars, seed)` gives a\n  deterministic app of any size, hashed from the generator's source and the\n  parameters. Its hot reload targets follow the playground's pragma form and\n  are listed in `bench-manifest.json`. `uv run python -m\n  reflex_bench.fixtures.generate --pages 10 DEST` writes one to look at.\n\n`ensure_fixture(ctx.cache_dir, describe, make)` keeps the app in\n`cache_dir/app` with a `fixture.json` stamp, and rebuilds it when the stamp no\nlonger matches: `setup_cache` directories are keyed by subject and parameters,\nnot by the app. `bump_marker(path, target, n)` sets a hot reload target's\nstring to `m-<n>-<target>`; the benchmark restores the module in `conclude`, so\nthe cached app stays the fixture its stamp describes.\n\nThe `lifecycle.*` benchmarks (`reflex_bench/suites/lifecycle.py`) time `init`,\n`compile`, `export`, `run` until HTTP-ready and `import reflex as rx; rx.App;\nrx.State` (the import alone is lazy), each in a cache state its id names\n(`cold`, `warm`, `incremental`); the module docstring lists which caches each\none starts from. No sample downloads anything: a subject downloads bun once,\ninto its shared `REFLEX_DIR` (`ctx.subject_cache_dir/reflex`), and installs the\nplayground's packages once, into its shared bun cache\n(`ctx.subject_cache_dir/bun-cache`); a cold state is a fresh directory that\nthese primed copies fill (`init.cold` gets a copy of bun, `compile.cold` a fresh\napp copy with the primed lockfile that links its packages from the cache), so a\nsample measures reflex and bun, not the network. Each `time` benchmark chooses its collector once, in\n`setup`, and records it in `dims` (`collector: cgroup | fallback`), so cgroup\npeaks and PSS peaks never share a series.\n\n## Fixture apps\n\nThe browser and hot reload benchmarks drive `examples/playground` (see its\nREADME for the element ids and `# bench:hmr-target` pragmas they rely on). The\nharness reads it from the checkout it runs in, never from the subject's\nenvironment, so `reflex-bench` must run from a reflex checkout.\n`reflex_bench.fixtures.prime(ctx)` copies it into the instance's cache directory\n(`<cache>/app/<arm>`: in an A/A run both arms share a cache directory, and two\nservers must not run in one app), without build output, and compiles it once\n(bun and the frontend packages), so the benchmarks' own starts are warm. The\nstaged copy is what the hot reload benchmarks edit; the checkout never changes.\nEvery sample records the playground's `.content-hash` in\n`extra[\"fixture_hash\"]`. `reflex_bench.fixtures.FIXTURES` maps the `app`\nparameter of the hot reload benchmarks to a staging function; `playground` is\nthe only one so far.\n\n## Event benchmarks\n\n`reflex_bench.suites.events` measures how many events the playground\n(`examples/playground`) answers and how fast. Each benchmark instance starts it\nonce as a production backend (`reflex run --env prod --backend-only`, one\ngranian worker), and each sample drives it for a few seconds with\n`reflex_bench.drivers.events`, a socket.io load generator that speaks reflex's\nevent websocket over `websockets` (no python-socketio). Sessions are browser\ntabs: each connects with its own token, hydrates like a page load, then sends\n`BenchState.set_seq*` events whose delta echoes a sequence number.\n\nThe grid holds the common points, about 30 minutes with the default policy.\nReflex's default state manager is disk, or redis with a `redis_url`, so every\nbenchmark runs on `disk` (and on `redis` when `REFLEX_REDIS_URL` is set), at 10\nsessions except `at_1hz` (200 sessions) and the fan-out (25 linked sessions).\nOnly `simple` also runs on `memory`, the framework's cost without state I/O,\nand at 50 sessions. Other sizes run by name with `--param`, e.g.\n`reflex-bench run 'events.complex.capacity' --param sessions=200`.\n\nCI minutes are scarce, so `smoke` runs two points, about 2 minutes per reflex\nwith the default policy: `events.simple.capacity[manager=disk,sessions=10]`\nand `events.simple.latency[manager=disk,sessions=10,rate=500]`. `daily` adds\nthe shared state at the same point,\n`events.shared_contention.capacity[manager=disk,sessions=10]` and\n`events.shared_contention.latency[manager=disk,sessions=10,rate=auto]`, and\n`events.shared_fanout.broadcast[manager=disk,linked=25]`. The other shapes,\nthe knee and `at_1hz` run with `--suite all` or by name.\n\n| Benchmark | Suites | Parameters | Load | Metrics |\n| --- | --- | --- | --- | --- |\n| `events.<shape>.capacity` | `smoke`, `daily` (simple, `manager=disk`, `sessions=10`) | `manager`, `sessions` 10 (simple: 10, 50) | closed loop, 3 s after 1 s | `throughput`, `service_p50`, `cpu_per_event` |\n| `events.<shape>.latency` | `smoke`, `daily` (simple, `manager=disk`, `sessions=10`, `rate=500`) | `manager`, `sessions`, `rate` | open loop, 5 s after 1 s | `response_p50`, `p90`, `p99`, `max`, `throughput`, `unanswered`, `cpu_per_event` |\n| `events.shared_contention.capacity` | `daily` (`manager=disk`, `sessions=10`) | `manager`, `sessions` 10 | the same as `capacity`, every session linked to one `rx.SharedState` board | the same as `capacity` |\n| `events.shared_contention.latency` | `daily` (`manager=disk`, `sessions=10`, `rate=auto`) | `manager`, `sessions`, `rate` | the same as `latency`, every session linked to one board | the same as `latency` |\n| `events.shared_fanout.broadcast` | `daily` (`manager=disk`, `linked=25`) | `manager`, `linked` 25 | one linked session sends, closed loop, 3 s after 1 s; answered once every linked session has the delta | `throughput`, `broadcast_p50`, `broadcast_p99`, `fanout_spread_p50`, `cpu_per_event` |\n| `events.simple.knee` | (`all`) | `manager`, `sessions` 10 | open loop at 10 % to 110 % of the capacity, 4 s after 1 s each | `knee_rate`, `low_load_p99` |\n| `events.sessions.at_1hz` | (`all`) | `manager`, `sessions` 200 | open loop, 1 ev/s per session, 10 s after 3 s | `response_p50`, `response_p99`, `unanswered`, `cpu_per_event` |\n| `selftest.events.calibrate` | `selftest` | | the generator against an echo server: closed loop, then open loop at 1500 ev/s | `closed_ceiling`, `open_lag_p99` |\n\n- **Shapes**: `simple` (`set_seq`), `complex` (three vars behind a chain of\n  three computed vars), `cross` (`get_state` of another state), `background` (a\n  background task). Background tasks may finish in any order, so for\n  `background` an answer that overtakes an earlier event counts as\n  `out_of_order` without making that event unanswered. `shared_contention`\n  (`BoardState.set_seq_shared`) links every session to one board, so each\n  event is fanned out to all the others.\n- **`manager`**: `memory` and `disk`, plus `redis` when `REFLEX_REDIS_URL` is set\n  in the harness's environment when the suite is imported. The URL reaches only\n  the redis instances: reflex uses redis whenever a URL is configured.\n- **`rate`**: `auto` offers half the capacity that a 2 s closed-loop probe\n  measures once per instance, so each arm of an `ab` run is loaded to the same\n  share of its own capacity; `--param rate=N` offers `N` events per second to\n  both, which compares the same absolute load. `smoke` and `daily` offer 500,\n  the same load from one day to the next.\n- **One backend per instance**: it starts in `setup`, which also warms it with\n  the probe, and stops in `cleanup`, so its samples share one warm server; in\n  an `ab` run both arms' backends are up, one idle while the other is measured.\n- **Open and closed loop**: the open loop sends on a fixed schedule whatever\n  the server does and times each answer from the *planned* send time, so a\n  stall counts in every event it delays (no coordinated omission); events\n  without an answer count as `unanswered`, never dropped. The closed loop sends\n  the next event when the previous one is answered: it measures capacity and\n  service time (answer minus actual send), never user latency.\n- **Rates count the window only**: `throughput` (`answered_rate`) is the\n  answers that arrived within the measured window divided by its length, the\n  same as `answered_per_second` summed. The drain after the window only decides\n  which events are `unanswered`; the answers it collects still count in the\n  response percentiles.\n- **Per run, not pooled**: every sample's percentiles come from that run's\n  events; `response_p99` of a run with fewer than 10 000 answered events is kept\n  with `p99_underpowered` in its extra data. Each sample's extra data also holds\n  a 120-bucket log histogram (10 μs to 100 s) for pooled percentiles on display.\n- **CPU per event** is the server tree's CPU time in the measured window divided\n  by the answered events: from its cgroup scope (`cpu_method: cgroup`) or,\n  without one, summed over its processes with psutil (`cpu_method: psutil`),\n  including the children they reaped, so a worker that exits in the window\n  still counts. A CPU time that goes back fails the sample.\n- **Pinning**: on Linux with four CPUs or more, the server runs on the lower\n  half of the physical cores (CPU 0 excluded) and the generator on the upper\n  half, so no core is shared between them through SMT (the kernel's\n  `thread_siblings_list`; without it every CPU counts as a core), with up to 4\n  generator processes (1 up to 10 sessions); `pinning` in the extra data\n  records the split.\n- **Self-check**: a load fails it when a generator process used more than\n  75 % of a core, when the p99 of the send lag (actual minus planned send\n  time) exceeds the larger of 1 ms and 10 % of the median response, or when\n  less than 98 % of the offered events went out in the window. The rules judge\n  the generator alone: a lag tail inflates the response tail by as much,\n  whatever caused it, so the sample fails with `generator saturated` at once\n  and is never taken again. `selftest.events.calibrate` fails the same way\n  when the generator cannot offer 1500 ev/s, three times the highest fixed rate\n  of the suite, against an echo server.\n\nNot parameters yet: injected redis latency, uvicorn instead of granian, and\nmore than one backend worker.\n\n## Memory benchmarks\n\n`reflex_bench.suites.memory` answers how much memory the playground takes,\nwhether it grows, and whether it fits a 512 MiB box. Samples are untimed:\nevery metric is bytes (lower is better) except `passed`. Each sample starts a\nfresh backend (`reflex run --env prod --backend-only`, one granian worker), as\nthe event benchmarks do; `memory.dev.idle` starts the dev server instead.\n\n| Benchmark | Suites | Parameters | One sample | Metrics |\n| --- | --- | --- | --- | --- |\n| `memory.compile.peak` | `daily` | `command` compile, export | `reflex compile` or `reflex export --env prod` of the compiled playground | `peak_mem` |\n| `memory.idle` | `smoke` (memory), `daily` | `manager` | 5 s after `/ping` answers, the median of three PSS reads a second apart | `pss`, `pss_anon`, `pss_file` |\n| `memory.idle.allocator` | (`all`) | `allocator` mimalloc, arena2 | the same with `PYTHONMALLOC=mimalloc` or `MALLOC_ARENA_MAX=2` | the same |\n| `memory.dev.idle` | `daily` | `manager` memory | the same for `reflex run --env dev`, backend and vite dev server, 10 s after the page answers HTTP (no browser, so vite has transformed only what that request needed); the USS of the node, bun and esbuild processes is split from the python ones in the extra data (`backend_uss_bytes`, `frontend_uss_bytes`) | the same |\n| `memory.per_session` | `daily` (`max_sessions=500`) | `manager`, `max_sessions` (1000) | hold 0, 50, 100, 250, 500 and 1000 idle sessions, fit PSS per session; disconnect; wait for the states to expire | `bytes_per_session`, `bytes_per_session_ci_hi`, `residual_after_disconnect`, `residual_after_expiry` |\n| `memory.leak` | `daily` (`events=50000`) | `manager`, `events` (100000) | a closed loop of 10 sessions while the tree's anonymous PSS is sampled | `passed`, `bytes_per_event_ci_hi` |\n| `memory.boot_512mb` | `daily` (memory) | `manager` | compile, then boot and serve, under `MemoryMax=512M` with swap off | `passed`, `peak_compile`, `peak_boot`, `peak_serve` |\n| `memory.boot.min_limit` | (`all`) | `manager` memory | bisects `MemoryMax` from 64 to 1024 MiB in 32 MiB steps over boot and serve | `min_limit` |\n\n- **Methods**: peaks come from a cgroup v2 scope's `memory.peak` where the host\n  can start one (user systemd, or `sudo systemd-run` on CI), else from PSS\n  sampled every 50 ms; steady-state values are the summed PSS of the server's\n  process tree on every host, with the scope's `memory.current`, `anon` and\n  `file` in the extra data when a scope holds the running server (the compile\n  peak reads its scope after the command exited, so it records only whether\n  the peak was reset). `memory_method` in the dims\n  (`cgroup` or `pss_sampling`) names the collector of the values, so cgroup and\n  PSS numbers never share a series. The limit benchmarks need a scope and fail\n  with `cgroup scopes are unavailable: <reason>` without one: nothing else can\n  enforce a limit. `reflex-bench doctor` shows what the host has.\n- **What PSS shows**: the memory the tree holds from the kernel, shared pages\n  split between the processes. CPython and glibc keep freed memory for reuse\n  and rarely hand it back, so a number that does not drop means the process did\n  not shrink, not that something leaks. File-backed pages are also split with\n  processes outside the tree that map the same files (the harness's own\n  interpreter), so `pss_file` moves by a few MB between otherwise identical\n  samples; `pss_anon` is the steadier trend.\n- **Per session**: the sessions connect and hydrate like page loads, then stay\n  idle, held by `reflex_bench.drivers.events.hold_sessions` in a separate\n  process. The server runs with `REFLEX_REDIS_TOKEN_EXPIRATION=<expiry_s>`\n  (hidden; 0, the default, sizes it from the sweep: its settling and reading\n  time, 2 s per hold and a 5 s margin, 23 s for 500 sessions), longer than the\n  sweep: no state manager frees a state when its session disconnects, reflex\n  0.9's memory and disk managers and 0.8's disk manager free it after the\n  expiration, and 0.8's memory manager never does. A sweep that outlasts the\n  expiration fails the sample; a slow host can raise `expiry_s`. The residuals\n  are PSS over the idle baseline. `baseline_bytes_per_session` in the extra\n  data is the same sweep against the in-harness echo server: the floor of a\n  Python `websockets` server, not of python-socketio (the harness does not\n  depend on python-socketio); it is measured once per instance, while the\n  first sample's states expire. The sweep's steps below `max_sessions` are 50,\n  100, 250 and 500, so the slope's t interval has at least three degrees of\n  freedom. The tree's PSS is flat within 0.2 MiB from the moment a hold is\n  ready (against steps of 8 to 47 MiB), so a step settles for 1 s and is read\n  three times 0.5 s apart: about 2.5 s each, and a sample about 40 s.\n- **Leak**: a 5 s closed-loop probe sizes the warmup (`warmup_events`, hidden,\n  5000) and the window (`events`, with 10 % of room); the tree is sampled every\n  hundredth of the window, between 0.1 s and 1 s apart. The x axis is the events\n  answered since the window started (`answered_per_second` of the load), the y\n  axis the anonymous PSS: file-backed pages do not leak. The sample fails with\n  `LeakDetected` when the upper end of the slope's 95 % interval exceeds\n  `tolerance_bytes_per_event` (hidden, 100 B, that is 100 MB per million\n  events) *and* each half of the window grows on its own (the lower end of its\n  slope's interval is above zero): heap warm-up flattens out and one allocator\n  step lifts one half only, a leak grows through both. One 1 MiB arena step in\n  50 000 events is about 30 B per event. An unanswered event or a failed\n  session fails the sample, since the event count would be wrong. `passed` is\n  the gate; the slope itself and the growth over the window are in the extra\n  data (`slope_bytes_per_event`, `growth_bytes`), since near zero they move by\n  hundreds of percent between identical runs. `timeline` in the extra data\n  holds up to 500 `[events, anonymous PSS, USS of the python processes]`\n  points.\n- **512 MiB**: the compile runs in one scope, the server boots and serves 5\n  closed-loop sessions for 5 s in another, each with `MemoryMax=<limit_mb>M`\n  (hidden, 512) and `MemorySwapMax=0`, and each scope is read before its tree\n  stops. A phase that fails, or any `oom` or `oom_kill` in `memory.events`,\n  fails the sample with `MemoryLimitExceeded` naming the phase, the counters,\n  the peak and the log tail. The peak is reset between boot and serve where\n  the kernel can (Linux 6.12 and later; `peak_reset` in the extra data says\n  so), else the serve peak includes the boot. The published 512 MiB number\n  comes from an\n  amd64 reference profile (Fly's `shared-cpu` machines are amd64); arm64 runs\n  are a trend.\n- **Allocators**: `--param allocator=mimalloc|arena2` also works on `memory.idle`,\n  `memory.per_session` and `memory.leak`, and puts the allocator in the dims.\n  mimalloc needs the subject's Python to be 3.13 or later.\n\nNot measured yet: a leak per session (connect/disconnect churn) or per page\nload, redis's `used_memory` per session, and peaks per phase within one command\n(they need `memory.peak` resets, Linux 6.12).\n\n**Finding a leak** (manual; tracemalloc slows the server and inflates its\nmemory, so it never runs in a measured sample). Add a temporary handler to the\napp's state:\n\n```python\n@rx.event\ndef heap_snapshot(self, seq: int):\n    import time, tracemalloc\n\n    tracemalloc.take_snapshot().dump(f\"/tmp/heap-{time.time_ns()}.bin\")\n    self.last_seq = seq\n```\n\nstart the backend with tracemalloc on in every process\n(`PYTHONTRACEMALLOC=25 GRANIAN_WORKERS=1 REFLEX_STATE_MANAGER_MODE=memory\nuv run reflex run --env prod --backend-only --backend-port 8000`), and drive\nit with the generator: a snapshot, a load, another snapshot.\n\n```python\nfrom reflex_bench.drivers.events import EventShape, LoadPlan, run_load, seq_payload\n\nstate = \"reflex___state____state.playground___state____bench_state\"\n\n\ndef load(handler: str, sessions: int, duration_s: float) -> None:\n    shape = EventShape(f\"{state}.{handler}\", seq_payload, state, \"last_seq_rx_state_\")\n    run_load(\n        LoadPlan(\n            backend_url=\"http://localhost:8000\",\n            reflex_version=None,\n            shape=shape,\n            sessions=sessions,\n            mode=\"closed\",\n            rate=None,\n            warmup_s=0,\n            duration_s=duration_s,\n        )\n    )\n\n\nif __name__ == \"__main__\":\n    load(\"heap_snapshot\", 1, 0.001)\n    load(\"set_seq\", 10, 60)\n    load(\"heap_snapshot\", 1, 0.001)\n```\n\nThen compare the two snapshots by line:\n`first, second = map(tracemalloc.Snapshot.load, sorted(glob.glob(\"/tmp/heap-*.bin\")))`\nand print `second.compare_to(first, \"lineno\")[:20]`.\n\n## Wire sizes\n\n`reflex_bench.suites.wire` counts the bytes that cross the event websocket: what\na slow link pays for, which no timing or CPU metric shows. One session connects\nto a fresh production backend per sample (`reflex run --env prod\n--backend-only`, one granian worker, the memory state manager) and sums the\npayload bytes of every frame it sends and receives (a text frame's UTF-8\nlength; the HTTP handshake is not a frame). Sizes are deterministic for a given\napp and reflex version, so every metric is exact and a sample is one run.\n\n| Benchmark | Suites | Parameters | One sample | Metrics |\n| --- | --- | --- | --- | --- |\n| `wire.hydrate` | `pr`, `smoke`, `daily` | | connect and hydrate the playground's index route, until the delta that sets `is_hydrated` | `hydrate_sent_bytes`, `hydrate_received_bytes`, `hydrate_frames` (received) |\n| `wire.event` | `pr`, `smoke` (simple), `daily` | `shape` simple, complex, cross, background | after hydration, one `BenchState.set_seq*` event: the request frame, and every frame received until the delta echoing its sequence number | `request_bytes`, `response_bytes`, `response_frames` |\n| `wire.navigate` | `pr`, `smoke` (item), `daily` | `route` counter (`/counter`), item (`/item/42`, the dynamic `/item/[item_id]` page) | after hydration of `/`, a client-side navigation: the `on_load_internal` frame the frontend's router effect sends from the new route, and every frame received until the delta that sets `is_hydrated` again | `request_bytes`, `response_bytes`, `response_frames` |\n| `wire.delta` | `daily` | `change` set_scalar, append_item, set_one_item, set_dict_key, update_row_field | the same for one small change to a large collection of the generated `wire_delta` app | `response_bytes` |\n\n- **Replies span frames**: `response_bytes` sums every frame from the request\n  until the echo, so 0.8.23's empty update before a background task's delta\n  counts, as does any delta of another state. The extra data keeps the echo\n  frame (`reply`), the largest frame, and `delta_bytes`, the bytes of each\n  substate's part of the deltas re-serialized compactly.\n- **Keepalives do not count**: an engine.io ping and its pong are timing, not\n  payload, so a slow run moves the same bytes as a fast one.\n- **`wire.navigate`** sends what the frontend sends on a route change: one\n  `on_load_internal` with the new route's `router_data`. `update_vars_internal`\n  goes first only once the browser holds a value of a client storage var (the\n  playground's `/storage` page sets some); a fresh browser holds none, on 0.8.23\n  and 0.9 alike, so neither the hydration nor the navigation sends it. The reply carries the root state's `router` and,\n  on the dynamic route, the route argument.\n- **`wire.delta`** does not use the playground: its `setup_cache` writes a\n  small app whose state holds 1000 ints in a list, 1000 keys in a dict and 200\n  dict rows, and compiles it. Every handler also sets `last_seq` (the echo), so\n  the deltas differ only by the collection they carry; `set_scalar` is the\n  control. A whole collection resent for a one-item change shows as\n  `response_bytes` far above the control's.\n- **Dims**: `fixture` names the app (`playground` or `wire_delta`); for\n  `wire.delta`, the entry's `fixture_hash` is the generated source's content\n  hash, so `compare` rejects a pair across a change to the generator.\n\n`AppProcess.t0` is the `time.perf_counter()` taken just before the spawn, the\norigin of every readiness time, and `AppProcess.log_lines()` returns the output\nwith the time each line was read (seconds since `t0`), so other clocks and log\nlines can be put on one timeline.\n\n## Driving a browser\n\n`reflex_bench.drivers.browser` drives headless Chromium through Playwright's\nsync API. Install the browser once:\n\n```console\n$ uv run playwright install --only-shell chromium\n```\n\nHeadless runs launch the headless shell, so the full Chromium is not needed\n(`--only-shell` exists from Playwright 1.49). On a bare CI runner add\n`--with-deps` for the system libraries, and cache `~/.cache/ms-playwright`\nkeyed on the runner's architecture. `reflex-bench doctor` reports whether a\nchromium is installed.\n\n```python\nfrom reflex_bench.drivers.browser import Browser\n\nself.browser = Browser(cpu_throttle=1)  # setup(): one browser per instance\nself.browser.start()  # the calling thread owns it\nresult = self.browser.interactive(self.app, \"/\")  # tier 3, also set in app.readiness\ntab = result.tab  # a page in a fresh context (cold cache); tab.page is Playwright's\ntab.watch(\"edit\", \"text\", \"#bench-marker-leaf\", marker)\nmark = tab.wait_mark(\"edit\", timeout=90)  # {\"perf\": ..., \"epoch\": ...}\n# conclude(): self.browser.close_tab(tab); cleanup(): self.browser.close()\n```\n\nEvery page gets `drivers/bench_page.js` as an init script, which runs before\nany page script in every document, reloaded ones included. The page emits the\n\"done\" signal itself: `tab.watch(id, kind, selector, expected)` has it record a\n*mark* the first time a condition holds (`present`, `text`, `changed`,\n`style:<property>` or `naturalWidth`), checked on every DOM mutation and every\nanimation frame (a computed style or a loaded image is no mutation); a watch,\nand its mark once recorded, survives a reload. `#bench-hydrated` is always watched: `interactive()` waits\nfor it (tier 3: the websocket connected and the first state update applied).\nThe script also collects paint, largest contentful paint, long task and long\nanimation frame entries (`tab.timings()`). `tab.set_alive()` tags the document\nand `tab.alive()` reads the tag back: a full reload loses it. Uncaught page\nerrors fail a sample (`tab.raise_errors()`), console errors and warnings are\ncounted (`tab.drain_console()`, the last error's text in `tab.last_error`), and\nwebsocket payload bytes and HTTP wire bytes (headers included, from the\nDevTools `Network.loadingFinished` events) are summed per page.\n\n**Clocks.** A mark carries `performance.now()` (since navigation start) and\n`Date.now()`. `browser.anchor`, the tightest of three back-to-back reads of\n`time.perf_counter()` and `time.time()` taken at start, maps page time onto\n`perf_counter()`: `anchor.perf_at(epoch) - app.t0` puts a page event on the\napp's timeline within 1 ms (`Date.now()`'s resolution) plus the anchor's\nspread, the harness's own share (well under a microsecond), which is stored\nwith the samples.\n\n**Threads.** The sync API refuses calls from any thread but the one that\nstarted it (`greenlet.error: Cannot switch to a different thread`), and\nteardown hooks run on a fresh thread after a timeout or Ctrl-C. `close()`\ncloses normally on the owner thread and kills from any other; `kill()` never\ntouches Playwright: it SIGKILLs the Playwright driver (the harness's child) and\nthe process group Chromium's root (the driver's child) leads with all its\nhelpers, both found at `start()`, so a hook still blocked in the page gets an\nerror at once. `close_tab()` from another thread kills the\nbrowser too: after a timeout the instance is over. Browsers still open when the\nharness exits are killed. A `Browser` belongs to one instance and arm; during\n`ab` two of them coexist. Playwright is imported on `start()`, which keeps\n`reflex-bench list` about 0.1 s faster.\n\n## Browser benchmarks\n\n| Id | Suites | What one sample measures |\n| --- | --- | --- |\n| `browser.dev.ready` | pr, daily, macro | `reflex run` start to `process_ready` (tier 1), `http_ready` (tier 2) and `interactive_ready` (tier 3), seconds since the spawn; also `nav_to_interactive` (in the page) and `fcp` |\n| `browser.preview.ready` | daily (reflex 0.9.8+) | the same with `--env preview` |\n| `browser.prod.ready` | daily | the same with `--env prod`, frontend build included |\n| `browser.prod.pageload[cpu=1\\|4]` | daily | loading `/` of one prod server in a fresh context (cold cache), CPU throttled 4 times with `cpu=4`, read as soon as the page is interactive: `fcp`, `lcp` (the same paint on the playground), `interactive`, `tbt` (long tasks' time beyond 50 ms before interactive), `ws_bytes`, `transfer_bytes` (wire bytes, headers included; both exact: the same page transfers the same bytes) |\n\nThe `ready` samples store the gaps between the tiers in `extra[\"gaps\"]`. Page\nload metrics are noisy: read the median and its confidence interval over at\nleast 6 runs (outliers are counted, not dropped).\n\n## Hot reload benchmarks\n\nEach `hmr.*` instance starts one app (`reflex run --loglevel debug`) and one\npage, then per sample rewrites the staged app and waits until the page shows\nthe change. The edit's content is built in `prepare`; `sample` writes it to a\nsibling temporary file and moves it over the target, taking `t0` just before\nthat one `os.replace`, and returns as soon as the page's mark is there.\n`latency` is the page's mark minus `t0`, on the wall clock of both. Every edit\nwrites a unique value, so a stale page never satisfies a watch. `conclude`\nwaits until the page has been quiet for 0.5 s (no pending watch, no DOM\nchange), restores the file and waits until the page shows the original and is\nquiet again, which is also the wait between edits. Every hook's waits share\none 90 s deadline. `warmup` is 3 edits.\n\n| Id | Edit | Done when the page shows |\n| --- | --- | --- |\n| `hmr.render.leaf` | the `leaf` pragma literal (index page only) | the new text in `#bench-marker-leaf` |\n| `hmr.render.root` | the `root` pragma literal (every page) | the new text in `#bench-marker-root` |\n| `hmr.handler` | the `handler` pragma literal, set by an event handler | the new value in `#bench-handler-value`; the harness clicks `#bench-handler` every 250 ms (`extra[\"clicks\"]`) |\n| `hmr.css` | the `.bench-hooks` font size in `assets/playground.css` | the computed font size |\n| `hmr.asset` | `assets/mark.svg` gets a `width` and `height` | `#bench-mark`'s `naturalWidth` (HTTP cache off); the harness refreshes the page every 250 ms (`extra[\"reloads\"]`) |\n| `hmr.reconnect` | none: SIGKILL of granian's worker, then SIGHUP to its supervisor, since granian's dev reloader never respawns a worker that died on its own | `#count` changes on `/counter`; the harness clicks `#increment` every 250 ms |\n| `hmr.watcher` | the `leaf` literal | `latency` is granian's `Changes detected` line (its `reload_tick` is 100 ms) |\n\nEvery benchmark but `hmr.watcher` has a `.preview` twin for `--env preview`\n(reflex 0.9.8+). Preview serves a static build that a hot reload rebuilds and\nthat shows after a refresh, so preview twins whose change needs a new page\nreload it (waiting for its load event) every 250 ms until it shows\n(`extra[\"reloads\"]`).\n\n`full_reloads` records whether the sample's page reloaded to show the change\n(the mark carries the document's `tab.alive()` tag; a reloaded document lost\nit). For the render, handler and reconnect benchmarks a reload is no hot\nupdate: `conclude` fails the sample with `FullReloadError`, also when the page\nreloads right after showing the hot update, so `latency` only holds hot\nupdates. For `hmr.css` a reload may be how the change shows: `latency` is the\ntime until it shows. A change the page never shows by itself (no hot update,\nno reload, within the deadline) fails the sample: the harness does not refresh\na dev page for it. The error then says when granian saw the change, when the\nreload's last `[timing]` line came and whether the page reloaded, so it tells\nwhich side dropped the change. A stylesheet hot update that vite logged\n(`[vite] ... hmr update`) 5 s ago without the page applying it fails the sample\nat once (`DroppedUpdateError`, naming the value the page still shows) instead\nof waiting the deadline out. `hmr.asset` refreshes the page itself in every\nmode: vite has no module for a file of `public/`, so a change to one reaches\nno page and a user refreshes for it; `latency` is the time until a refresh\nshows the new file and `extra[\"reloads\"]` counts the refreshes.\n`extra[\"hops\"]` places each sample's backend steps, in seconds\nsince the edit: `watcher_seen_s` (granian's line), `compile_done_s` (the\nreload's last `[timing]` line) and `dom_updated_s` (the page's mark).\n\n## Size budgets\n\n`size.export[app=playground]` (suites `pr` and `daily`) measures what a\nproduction build of `examples/playground` ships. Its `setup` copies the files\ngit tracks of the example into the instance's work directory (each arm of an\n`ab` run gets its own copy; `--keep` keeps it) and runs `reflex export\n--frontend-only --no-zip --env prod` there; bun stays cached in reflex's data\ndirectory under the cache directory. `sample` then measures the files on disk.\nOne export gives every metric, and every metric is exact, so one sample is\ntaken:\n\n| Metric | What |\n| --- | --- |\n| `initial_raw`, `initial_gzip`, `initial_brotli` | The JS and CSS the first page loads: the files the prerendered `index.html` references with `<link rel=\"modulepreload\">`, `<link rel=\"stylesheet\">` or `<script src>`. URLs of other hosts are not part of the build. |\n| `total_raw`, `total_gzip`, `total_brotli` | Every file of `.web/build/client` except compression sidecars. |\n| `chunks` | The `.js` files of `.web/build/client/assets`. |\n| `web_dir` | The regular files under `.web` outside `node_modules` (build output, compiled pages, templates). |\n| `node_modules` | The regular files under `.web/node_modules`. Symlinks are neither followed nor counted, here and in `web_dir`. |\n\nThe harness compresses each file on its own, gzip at level 9 (`mtime=0`) and\nbrotli at quality 11. Reflex 0.9 writes `.gz` sidecars next to the build's files\n(`.br` and `.zst` too when configured) and 0.8.23 writes none, so sidecars are\nnever measured, only summed into the extra data's `sidecar_bytes`. Each sample's\nextra data also holds the per-file breakdown `files`: `raw`, `gzip`, `brotli` and\n`initial` for each file of the client build, keyed by its path with the content\nhash of names in `assets/` replaced (`assets/chunk-5KNZJZUH-q9CrfzJj.js` becomes\n`assets/chunk-5KNZJZUH-HASH.js`; `#2` marks a second name that differed only in\nits hash), plus `initial_files` in page order, `html` (the page parsed),\n`reflex_version`, `fixture_hash` (the playground's committed `.content-hash`,\nthe hash the result series are keyed on and that CI keeps current; an\nuncommitted playground edit shows in the subject's `dirty` flag instead),\n`bun_lock` (the hash of `.web/bun.lock`) and the `compressors`' versions. Apps\nwith a `frontend_path` are not s\n\n<!-- [TRUNCATED AT 50KB] -->","isInternal":false,"tokens":13178,"sizeBytes":50035},{"name":"README.md","path":"packages/reflex-build-sdk/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-build-sdk/README.md","title":"reflex-build-sdk Documentation","category":"plugin-manifest","format":"markdown","content":"# reflex-build-sdk\n\nPython client for the [Reflex Build](https://build.reflex.dev) API, with synchronous and asynchronous interfaces.\n\nInstall it with the HTTP library the client should send requests with:\n\n```bash\npip install \"reflex-build-sdk[httpx2]\"   # ReflexBuild and AsyncReflexBuild\npip install \"reflex-build-sdk[aiohttp]\"  # AsyncReflexBuild only\npip install \"reflex-build-sdk[httpx]\"    # ReflexBuild and AsyncReflexBuild\n```\n\nWithout any of them, pass the client a [transport](#transports) of your own.\n\n```python\nfrom reflex_build_sdk import ReflexBuild\n\nwith ReflexBuild() as client:\n    me = client.auth.me()\n    print(me.email, me.tier)\n```\n\n```python\nfrom reflex_build_sdk import AsyncReflexBuild\n\nasync with AsyncReflexBuild() as client:\n    me = await client.auth.me()\n```\n\n## Apps and projects\n\n```python\nfrom reflex_build_sdk import ReflexBuild\n\nwith ReflexBuild() as client:\n    projects = client.projects.search(\"default\")\n    project = projects[0] if projects else client.projects.create(\"default\")\n    app = client.apps.create(\"dashboard\", project_id=project.id)\n    client.apps.secrets.set(app.id, {\"OPENAI_API_KEY\": \"sk-...\"})\n\n    for deployment in client.apps.history(app.id):\n        print(deployment.status, deployment.url)\n\n    for record in client.apps.logs(app.id, search=\"error\"):\n        print(record.timestamp, record.message)\n```\n\n`client.apps` lists, creates, renames, moves, starts, stops, pauses, scales, rolls back and deletes apps, changes their settings, and reads their status, running deployment, deployment history and runtime logs; `client.apps.secrets` manages their secrets. `client.projects` lists, searches, creates, renames and deletes projects and reads their audit logs, with `projects.roles` (including custom roles), `projects.members` and `projects.teams` for access control. `AsyncReflexBuild` has the same methods as coroutines, with `logs` as an async iterator.\n\n### Custom domains\n\n```python\nfor record in client.apps.domains.add(app.id, \"app.example.com\").values():\n    print(record.type, record.name, record.value)\n\ndomain = client.apps.domains.get(app.id)\nprint(domain.status, domain.status_detail)\n```\n\n`domains.add` returns the DNS records to create, and `domains.get` checks them and reports whether the domain is ready to serve the app. Custom domains need the Pro or Enterprise plan.\n\n## Deploying\n\n```python\nfrom reflex_build_sdk import DeploymentFailedError, ReflexBuild\n\nwith ReflexBuild() as client:\n    urls = client.apps.reserve_hostname(app.id, app.name)\n    # Export the app against urls.frontend_url and urls.backend_url, e.g. with\n    # `reflex export`, producing backend.zip and frontend.zip.\n    deployment_id = client.deployments.create(\n        app.id,\n        backend=\"backend.zip\",\n        frontend=\"frontend.zip\",\n        regions={\"sjc\": 1},\n        on_upload_progress=lambda sent, total: print(f\"{sent}/{total} bytes\"),\n    )\n    try:\n        report = client.deployments.wait(deployment_id, on_status=print, timeout=900)\n    except DeploymentFailedError as error:\n        print(error.report.reason, error.report.guidance)\n        print(error.report.build_log_excerpt)\n        raise\n```\n\n`deployments.create` streams the archives straight to storage, then submits the deployment. `deployments.wait` returns the deployment's report once it is running, or awaiting approval (`report.status == \"AwaitingApproval\"`), and raises `DeploymentFailedError` if it fails. `deployments.status`, `report` and `build_logs` read a deployment's progress, and `regions` and `vm_types` list what can be deployed to.\n\n### Environments\n\nGive an app a pipeline of a dev and a production environment:\n\n```python\npipeline = client.apps.environments.enable(app.id)\nproduction_id = pipeline.production_environment_id\n```\n\nAn app that has a pipeline already is read rather than enabled again, which fails:\n\n```python\ndev, production = client.apps.environments.list(app.id)\nproduction_id = production.id\n```\n\nDeployments go to the first environment, and later ones run a version promoted from the one before:\n\n```python\ndeployment_id = client.deployments.create(\n    app.id, backend=\"backend.zip\", frontend=\"frontend.zip\"\n)\nclient.deployments.wait(deployment_id)\npromotion = client.apps.environments.promote(app.id, production_id)\nclient.deployments.wait(promotion.deployment_id)\n```\n\nEach environment has its own secrets and URL, and production keeps the app's own id and history. `environments.create`, `update`, `reorder`, `copy_missing_secrets` and `delete` manage the rest of the pipeline. Pipelines need the Enterprise plan.\n\n### Managed database\n\n```python\ndatabase = client.apps.database.create(app.id)\nprint(database.masked_connection_string)\n```\n\n`client.apps.database` creates a Postgres database for an app, shared by all of its environments, and sets its connection strings as secrets, `DATABASE_URL` among them, which each environment picks up on its next deployment. Creating or deleting a database needs a token with full access, which `reflex login` tokens are not, and an app with its own `DATABASE_URL` secret is refused.\n\n### Signing users in\n\n```python\nclient.apps.sign_in.enable(app.id)\nclient.apps.sign_in.set_audience(app.id, \"invited\")\nclient.apps.sign_in.invite(app.id, \"someone@example.com\")\n```\n\n`client.apps.sign_in` lets an app's users sign in with their Reflex accounts, through `rxe.AuthPlugin` from `reflex-enterprise`. It sets the app's sign-in settings as secrets, which take effect when the app is next deployed with `rxe.AuthPlugin`, chooses who may sign in, and lists, exports and blocks the app's users. Restricting who may sign in and inviting addresses need the Pro or Enterprise plan. Changing sign-in needs a token with full access; tokens from `reflex login` are refused.\n\n### Third-party connections\n\n```python\n# Inside a deployed app, which is started with its own access token.\nwith ReflexBuild() as client:\n    token = client.apps.connections.credential(app_id, \"openai\").access_token\n    # ... and for one of the app's users:\n    token = client.apps.connections.credential(\n        app_id, \"openai\", end_user=user_id\n    ).access_token\n```\n\n`client.apps.connections` calls third-party services an app is connected to without the app holding their keys: Reflex Build stores the credentials and hands out a live one per call, so read one for each call rather than storing it. `connect_link` starts a connection and returns the page to send someone to, `status` and `list` report what is connected, and `disconnect` ends it. A connection belongs either to the app or to one of its users, named with `end_user`. These need the app's own token, so a client built with no arguments inside a deployed app is already the right one.\n\n## Authentication\n\nThe client uses the `token` argument, or the `REFLEX_ACCESS_TOKEN` environment variable when none is passed.\n\nTo log in through the browser:\n\n```python\nimport webbrowser\n\nfrom reflex_build_sdk import ReflexBuild\n\nwith ReflexBuild() as client:\n    login = client.auth.begin_login()\n    print(f\"Approve the login at {login.url}\")\n    webbrowser.open(login.url)\n    token = client.auth.finish_login(login, timeout=600)\n\nwith ReflexBuild(token=token) as client:\n    print(client.auth.me().email)\n```\n\n`client.auth.tokens.revoke_self()` revokes the client's own token, which any token may do. Create a token for CI with `client.auth.tokens.create(\"ci\", expires_in_days=30)`, whose `.token` holds the value, and rotate or revoke one with `client.auth.tokens.refresh(token)`, whose `.token` holds the new value, and `client.auth.tokens.revoke(token)`. If a refresh answers `previous_revoked=False`, the old token is still live and needs revoking. Managing other tokens needs a token with full access, which `reflex login` tokens are not.\n\n`client.usage.balance()` reports how much of the organization's plan allowance is used, and `client.usage.history()` iterates over its charges and credits.\n\n### Pointing at another deployment\n\nThe client sends its requests to `https://build.reflex.dev`, or to the `base_url` argument, the `REFLEX_BUILD_BACKEND_URL` environment variable or `REFLEX_CLOUD_BACKEND_URL`, in that order. `begin_login` builds its approval URL the same way, from `ui_url`, `REFLEX_BUILD_URL` or `REFLEX_CLOUD_URL`, and falls back to the client's `base_url`. `reflex-hosting-cli` reads only the `REFLEX_CLOUD_*` names, so set those too for `reflex deploy` to reach the same deployment.\n\n## Security reviews\n\n```python\nreview_id = client.security_reviews.submit(\"source.zip\")\nresult = client.security_reviews.wait(review_id, timeout=600)\nfor violation in result.violations:\n    print(violation.severity, violation.file_path, violation.line, violation.message)\n```\n\nSecurity reviews need the Pro or Enterprise plan.\n\n## Google Cloud\n\nApps can run on an organization's own Google Cloud instead of Reflex Build:\n\n```python\nstatus = client.providers.gcp_status(client.auth.me().org_id)\nif status.configured and status.allowed:\n    client.apps.set_provider(app.id, \"gcp\")\n    client.apps.set_instance_bounds(app.id, min_instances=1, max_instances=10)\n```\n\nRunning on Google Cloud needs the Enterprise plan. `client.apps.set_full_deploy` also serves an app's frontend from Google Cloud, and `client.providers.cloud_run_manifest()` returns the Dockerfile and script to deploy to Cloud Run yourself.\n\nOrganization admins connect Google Cloud projects with a service account key:\n\n```python\nwith open(\"key.json\") as key_file:\n    client.providers.connect_gcp(\n        client.auth.me().org_id,\n        service_account_key=key_file.read(),\n        project_number=\"123456789012\",\n        region=\"us-central1\",\n    )\n```\n\n`client.providers.gcp_connections` adds, updates, verifies and removes further projects, rotates their keys and chooses the default, and `client.providers.disconnect_gcp` removes them all. These need a token with full access.\n\n## Errors\n\nEvery exception derives from `reflex_build_sdk.ReflexBuildError`. Error responses raise a subclass of `APIStatusError` matching the status code (`AuthenticationError`, `NotFoundError`, ...), carrying `status_code`, the server's `detail`, the `code` naming the condition where the API names one (e.g. `\"not_connected\"`), and the `request_id` to quote to support. Failed requests are retried up to `max_retries` times when repeating them cannot apply them twice: requests that never reached the server or were turned away with 408 or 429, and requests that are harmless to repeat (`GET`, `HEAD`, `OPTIONS` and `PUT` requests, and calls such as `apps.environments.update` that settle on the same result) that timed out, lost their connection, or got a 500, 502, 503 or 504 response.\n\n## Transports\n\n`AsyncReflexBuild` sends requests with the first installed of [aiohttp](https://docs.aiohttp.org), [httpx2](https://github.com/pydantic/httpx2) and [httpx](https://www.python-httpx.org), and `ReflexBuild` with httpx2, or httpx if httpx2 is not installed. Pass a transport from `reflex_build_sdk.transports` to configure the HTTP client, e.g. for proxies, or to pick the HTTP library:\n\n```python\nimport aiohttp\nimport httpx2\nfrom reflex_build_sdk import AsyncReflexBuild, ReflexBuild\nfrom reflex_build_sdk.transports import (\n    AiohttpTransport,\n    AsyncHttpx2Transport,\n    Httpx2Transport,\n)\n\n# Reads HTTP_PROXY, HTTPS_PROXY and NO_PROXY from the environment.\nasync with aiohttp.ClientSession(trust_env=True) as session:\n    async with AsyncReflexBuild(transport=AiohttpTransport(session)) as client:\n        ...\n\nclient = AsyncReflexBuild(transport=AsyncHttpx2Transport())\nclient = ReflexBuild(\n    transport=Httpx2Transport(httpx2.Client(proxy=\"http://proxy:8080\"))\n)\n```\n\nTo use another HTTP library, implement the `Transport` or `AsyncTransport` protocol.\n\nTo wrap the synchronous SDK's default transport without choosing an HTTP library,\ncall `reflex_build_sdk.transports.default_transport()`. It selects httpx2 when\ninstalled, otherwise httpx. Close the returned transport when finished; clients\nleave explicitly supplied transports open.\n","isInternal":false,"tokens":2733,"sizeBytes":12051},{"name":"README.md","path":"packages/reflex-components-code/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-components-code/README.md","title":"reflex-components-code Documentation","category":"plugin-manifest","format":"markdown","content":"# reflex-components-code\n\nReflex code display components.\n","isInternal":false,"tokens":11,"sizeBytes":58},{"name":"README.md","path":"packages/reflex-components-core/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-components-core/README.md","title":"reflex-components-core Documentation","category":"plugin-manifest","format":"markdown","content":"# reflex-components-core\n\nUI components for Reflex.\n","isInternal":false,"tokens":10,"sizeBytes":52},{"name":"README.md","path":"packages/reflex-components-dataeditor/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-components-dataeditor/README.md","title":"reflex-components-dataeditor Documentation","category":"plugin-manifest","format":"markdown","content":"# reflex-components-dataeditor\n\nReflex dataeditor components.\n","isInternal":false,"tokens":12,"sizeBytes":62},{"name":"README.md","path":"packages/reflex-components-gridjs/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-components-gridjs/README.md","title":"reflex-components-gridjs Documentation","category":"plugin-manifest","format":"markdown","content":"# reflex-components-gridjs\n\nReflex gridjs components.\n","isInternal":false,"tokens":12,"sizeBytes":54},{"name":"README.md","path":"packages/reflex-components-internal/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-components-internal/README.md","title":"reflex-components-internal Documentation","category":"plugin-manifest","format":"markdown","content":"# reflex-components-internal\n\nReflex internal components.\n","isInternal":false,"tokens":11,"sizeBytes":58},{"name":"README.md","path":"packages/reflex-components-lucide/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-components-lucide/README.md","title":"reflex-components-lucide Documentation","category":"plugin-manifest","format":"markdown","content":"# reflex-components-lucide\n\nReflex lucide components.\n","isInternal":false,"tokens":13,"sizeBytes":54},{"name":"README.md","path":"packages/reflex-components-markdown/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-components-markdown/README.md","title":"reflex-components-markdown Documentation","category":"plugin-manifest","format":"markdown","content":"# reflex-components-markdown\n\nReflex markdown components.\n","isInternal":false,"tokens":11,"sizeBytes":58},{"name":"README.md","path":"packages/reflex-components-moment/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-components-moment/README.md","title":"reflex-components-moment Documentation","category":"plugin-manifest","format":"markdown","content":"# reflex-components-moment\n\nReflex moment components.\n","isInternal":false,"tokens":11,"sizeBytes":54},{"name":"README.md","path":"packages/reflex-components-plotly/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-components-plotly/README.md","title":"reflex-components-plotly Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-components-plotly%2FREADME.md -->","isInternal":false,"tokens":13,"sizeBytes":54},{"name":"README.md","path":"packages/reflex-components-radix/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-components-radix/README.md","title":"reflex-components-radix Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-components-radix%2FREADME.md -->","isInternal":false,"tokens":11,"sizeBytes":52},{"name":"README.md","path":"packages/reflex-components-react-player/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-components-react-player/README.md","title":"reflex-components-react-player Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-components-react-player%2FREADME.md -->","isInternal":false,"tokens":12,"sizeBytes":66},{"name":"README.md","path":"packages/reflex-components-recharts/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-components-recharts/README.md","title":"reflex-components-recharts Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-components-recharts%2FREADME.md -->","isInternal":false,"tokens":12,"sizeBytes":58},{"name":"README.md","path":"packages/reflex-components-sonner/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-components-sonner/README.md","title":"reflex-components-sonner Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-components-sonner%2FREADME.md -->","isInternal":false,"tokens":13,"sizeBytes":54},{"name":"README.md","path":"packages/reflex-docgen/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-docgen/README.md","title":"reflex-docgen Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-docgen%2FREADME.md -->","isInternal":false,"tokens":11,"sizeBytes":63},{"name":"README.md","path":"packages/reflex-hosting-cli/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-hosting-cli/README.md","title":"reflex-hosting-cli Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-hosting-cli%2FREADME.md -->","isInternal":false,"tokens":280,"sizeBytes":1329},{"name":"README.md","path":"packages/reflex-otel/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-otel/README.md","title":"reflex-otel Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-otel%2FREADME.md -->","isInternal":false,"tokens":1480,"sizeBytes":5986},{"name":"README.md","path":"packages/reflex-release/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-release/README.md","title":"reflex-release Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-release%2FREADME.md -->","isInternal":false,"tokens":12132,"sizeBytes":50270},{"name":"README.md","path":"packages/reflex-site-shared/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-site-shared/README.md","title":"reflex-site-shared Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-site-shared%2FREADME.md -->","isInternal":false,"tokens":1087,"sizeBytes":5241},{"name":"README.md","path":"packages/reflex-workflow/benchmarks/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-workflow/benchmarks/README.md","title":"benchmarks Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-workflow%2Fbenchmarks%2FREADME.md -->","isInternal":false,"tokens":1514,"sizeBytes":5375},{"name":"README.md","path":"packages/reflex-workflow/examples/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-workflow/examples/README.md","title":"examples Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-workflow%2Fexamples%2FREADME.md -->","isInternal":false,"tokens":834,"sizeBytes":3536},{"name":"README.md","path":"packages/reflex-workflow/README.md","rawUrl":"https://raw.githubusercontent.com/reflex-dev/reflex/HEAD/packages/reflex-workflow/README.md","title":"reflex-workflow Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/reflex-dev/reflex?path=packages%2Freflex-workflow%2FREADME.md -->","isInternal":false,"tokens":6034,"sizeBytes":25692}],"systemPromptSnippet":"<yakaai_skills repo=\"reflex-dev/reflex\">\n<!-- File: AGENTS.md (Tokens: ~2584 | Category: root-instruction) -->\n# Coding Agent Guidelines\n\nReflex: Python web **framework** compiling to React. Monorepo using uv workspace — main package in `reflex/`, sub-packages in `packages/`, docs site in `docs/`.\n\n## Workflow\n\n1. **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.\n2. **Bugfixes:** write a regression test that fails before writing the fix.\n3. **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.\n\n## Commands\n\nUse `uv` for everything — never bare `python` or `python3`.\n\n```\nuv sync                                                          # install deps\nuv run pytest tests/units --cov --no-cov-on-fail --cov-report=   # unit tests (>=72% coverage)\nuv run pytest tests/integration                                  # integration tests (slow)\nuv run ruff check .                                              # lint\nuv run ruff format .                                             # format\nuv run pyright reflex tests                                      # type check\nuv run python scripts/check_min_deps.py                          # validate each package's declared minimum dep versions (pyright in isolated min-version envs; workspace siblings resolve from locally built wheels, all other deps from PyPI). CI passes --wheelhouse instead, reusing the build jobs' artifacts\nuv run python scripts/check_min_deps.py --check-dev-pins [pkg]    # fail if pkg (default: all) declares an unpublishable *.dev dependency pin (the publish workflow runs the same gate via `reflex-release check-dev-pins`)\nuv run reflex-release sync                                       # regenerate the release workflows after editing [tool.reflex-release] or the reflex-release templates\nuv run python scripts/make_pyi.py                                # regenerate .pyi stubs\nuv run pre-commit run --all-files                                # all pre-commit hooks\n```\n\n## Layout\n\n```\nreflex/                 # main framework package (app, state, compiler, components, utils, istate)\npackages/               # workspace sub-packages (reflex-base, reflex-components-*, reflex-docgen, reflex-components-internal)\ntests/units/            # unit tests, mirrors source tree\ntests/integration/      # Selenium integration tests (run in dev+prod modes)\n  tests_playwright/     # Playwright integration tests (preferred for new tests)\ntests/benchmarks/       # performance benchmarks\ndocs/                   # documentation site (separate workspace member)\n```\n\n## Code style\n\n- Concise, robust code. Reflex is a framework used in many ways — handle edge cases without unnecessary complexity.\n- 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.\n- Don't add expensive workarounds (e.g. `isinstance` checks) to paper over type-level problems — fix the root cause instead.\n- Don't repeat validation or be over-defensive; trust data that was already validated upstream.\n- Think in CPU cycles: avoid unnecessary data copies, redundant allocations, and gratuitous indirection.\n- Extract duplicated code into parameterized helpers.\n- No block comments (`# --- Section ---`, `# ============`). Plain inline comments only.\n- Be cautious creating new public APIs — they must be documented and supported long-term.\n- Google-style docstrings on all functions: one-line summary, optional detail sentence(s), then Args/Returns (or Yields)/Raises.\n- Prefer imports at the top of the module in isort order. Only use inline imports when necessary to avoid circular dependencies.\n\n## Testing\n\n- Write comprehensive tests for new/changed features; extend existing test files where possible.\n- Test functions at module level, not wrapped in classes.\n- **Unit tests:** `tests/units/`, run with `uv run pytest tests/units`.\n  - 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`).\n- **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.\n\n### Integration test patterns\n\nApps as factory functions, run via `AppHarness`:\n\n```python\ndef SomeApp():\n    import reflex as rx\n\n    class State(rx.State):\n        value: str = \"\"\n\n    def index():\n        return rx.box(rx.text(State.value))\n\n    app = rx.App()\n    app.add_page(index)\n\n\n@pytest.fixture(scope=\"module\")\ndef some_app(tmp_path_factory) -> Generator[AppHarness, None, None]:\n    with AppHarness.create(\n        root=tmp_path_factory.mktemp(\"some_app\"), app_source=SomeApp\n    ) as harness:\n        yield harness\n```\n\nPlaywright tests use the `page` fixture and navigate to `harness.frontend_url`. Utilities in `tests/integration/utils.py` (polling, event ordering, storage).\n\n## .pyi stubs\n\nWhen 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.\n\n## CI workflows\n\nBranch rules require one check per workflow, listed in\n`.github/rulesets/main-required-checks.json`. Check names are matched literally —\nno wildcards — so two rules follow:\n\n- **A required workflow must not filter its `pull_request` trigger.** A workflow\n  a path filter skips never reports its checks, so a required check on it blocks\n  the merge forever. Filter in a `changes` job instead and gate the real jobs on\n  `if: needs.changes.outputs.run == 'true'` — a job skipped by `if:` reports as a\n  pass. `push` triggers may keep their filters; nothing gates a merge there. So\n  may a workflow that blocks no merge — absent from the ruleset and listed in\n  that test's `ADVISORY` — where the filter costs a run rather than a merge.\n- **Every merge-blocking workflow ends in a gate job** named `<workflow>-gate`,\n  which collapses it into one check name that matrix expansion cannot move. The\n  exception is a workflow with one job whose name cannot drift — `pre-commit`,\n  `changelog` — which the ruleset requires by that name (`DIRECTLY_REQUIRED` in\n  the test). A gate looks like:\n\n```yaml\n  unit-tests-gate:\n    needs: [changes, unit-tests, unit-tests-macos]  # every other job\n    if: always()  # not !cancelled(): a cancelled run would report a pass\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@... # v6.0.2\n        with:\n          persist-credentials: false\n      - uses: ./.github/actions/ci_gate\n        with:\n          needs: ${{ toJSON(needs) }}\n```\n\nAdding a job means adding it to the gate's `needs`; adding a workflow means\nadding its gate to the ruleset. `tests/units/test_workflow_gates.py` fails when\neither drifts. Every matrix leg blocks through its gate, pre-release Python\nversions included, so leave `continue-on-error` off a gated job. A workflow\ndisabled in the repository's Actions settings never reports, which no test can\nsee: disabling one means moving it to `ADVISORY` and out of the ruleset, or every\nmerge waits on it.\n\n## Changelog fragments\n\nUser-facing changes need a news fragment in the `news/` directory of each\npackage they touch (the repo root's `news/` for `reflex`), named\n`+<slug>.<type>.md`. Putting the PR number in the name (`<PR number>.<type>.md`)\nis optional: the release process renames an orphan fragment when it can identify\nthe PR that added it, so its entry links to that PR. Don't push a commit just to\nrename one. Types: `breaking`, `deprecation`, `feature`, `bugfix`,\n`performance`, `docs`, `misc`.\n\nWrite for external downstream users, not for reviewers. Every entry links to\nits PR, so motivation, narrative, and implementation details belong in the PR\nand the commit message — a reader who wants them will follow the link. Keep the\nfragment to a sentence or two saying what changed and what it means for a user:\n\n> Reduce published wheel and sdist size by removing misplaced generated artifacts.\n\nBrevity is about the narrative, not the substance: whatever is genuinely useful\ndownstream belongs in the fragment. A brief usage example for a new feature, or\nthe before/after of converting deprecated usage to the supported style, earns\nits place. Once it runs past a few sentences and a small code block, it is\ndocumentation — write it under `docs/` and let the fragment link there.\n\nCI requires a fragment for every package whose source the PR touches; the\n`skip-changelog` label waives it for changes that are genuinely not user-facing.\n\n## Sibling dependency floors\n\nWhen a package needs an unreleased change in a workspace sibling, raise its\nfloor on that sibling to the `.dev0` of the sibling's next version. Every\npackage derives its version with `bump = true`, so each commit after its newest\ntag builds as a dev release of that next version:\n\n- after `reflex-base-v0.9.12`: `reflex-base >= 0.9.13.dev0`\n- after `reflex-components-core-v0.9.10.post1`: `reflex-components-core >= 0.9.10.post2.dev0`\n\nSuch a floor excludes every release up to that tag and is met by every later\ncommit, so check-min-deps passes. A post release of the sibling cut after the\nfloor was written leaves main building below it; re-floor at that post release.\nReleasing the dependent lifts it to the first\npublished version that satisfies it (see `packages/reflex-release/README.md`,\n\"Dependency pins across a release\"). A floor the workspace can't meet fails\ncheck-min-deps with \"builds as ... here\".\n\n## Breaking changes and deprecation\n\nReflex has downstream users — don't break them. Provide a fallback path during deprecation.\n\n**Runtime warning** via `console.deprecate()`:\n```python\nfrom reflex_base.utils import console\n\nconsole.deprecate(\n    feature_name=\"OldFeature\",\n    reason=\"Use NewFeature instead.\",\n    deprecation_version=\"<next dot version of latest git tag>\",\n    removal_version=\"1.0\",\n)\n```\nSet `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.\n\n**Type-level deprecation** for deprecated methods/overloads using `typing_extensions.deprecated`, always inside a `TYPE_CHECKING` guard to avoid double warnings:\n```python\nfrom __future__ import annotations\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from typing_extensions import deprecated\n\n    @deprecated(\"Use new_method() instead\")\n    def old_method(self) -> str: ...\n```\n\n## Checklist\n\nBefore submitting:\n1. Tests pass with adequate coverage\n2. `uv run ruff check .` and `uv run ruff format .` clean\n3. `uv run pyright reflex tests` passes\n4. `pyi_hashes.json` updated if components changed\n5. Documentation updated if user-facing behavior changed\n6. News fragment added for user-facing changes\n7. Deprecation warnings added if breaking changes introduced\n\n<!-- File: CLAUDE.md (Tokens: ~3 | Category: claude-rule) -->\nAGENTS.md\n\n<!-- File: .claude/skills/prerelease-test/references/agent-brief.md (Tokens: ~1742 | Category: anthropic-skill) -->\n# The agent brief\n\nCopy this into the campaign scratchpad (e.g. `$SB/AGENT_BRIEF.md`), fill the `<...>` placeholders,\nand tell every test agent to read it first. It carries the rules that keep results trustworthy and\nthe environment traps that otherwise get rediscovered — expensively — by each agent in turn.\n\nKeep it in a file rather than pasting it into each prompt: agents re-read it when they get\nconfused, and updating one file updates the whole fleet.\n\n---\n\n## BRIEF TEMPLATE (copy from here)\n\nYou are one of several agents independently exercising the reflex `<VERSION>` pre-release\n(published `<DATE>`) as a real-world user of the framework. Your job: build small sample apps and\nrepro scripts for your assigned feature cluster, run them END-TO-END (real server, real Chromium),\nand hunt for anomalies. You REPORT issues; you never fix framework code.\n\n### HARD RULES\n\n1. **NEVER install reflex (or any workspace package) from the local checkout at `<REPO>`.** No\n   `uv sync`, no `uv run`, no `pip install -e`, no `uv pip install .` anywhere under it.\n   Everything installs from PyPI. We are testing what users receive, not what the tree contains.\n2. **Never run python with the checkout as your working directory.** `<REPO>/reflex/` shadows the\n   installed package, so `import reflex` silently picks up unreleased source and your results\n   become fiction. Run scripts from a neutral directory and start each repro with an assertion\n   naming the venv whose python is running it — the shared one below, or your own:\n   ```python\n   import reflex\n\n   assert \"<VENV_PATH>\" in reflex.__file__, reflex.__file__\n   ```\n   A guard that names some other venv fails on every run and gets deleted, which leaves you with\n   no guard at all.\n3. Reading the checkout is fine and encouraged — release source is on branch `<PRERELEASE_BRANCH>`.\n   For PR context load the GitHub MCP tools via ToolSearch (`select:mcp__github__pull_request_read`).\n4. Do NOT run any `git` write commands (add/commit/checkout/...) in the checkout. The orchestrator\n   commits artifacts.\n5. Do NOT fix bugs you find — record precise repro steps instead.\n6. Kill every server and browser you start before you finish (track PIDs; verify with `ps`). Other\n   agents share this machine — run at most ONE dev server at a time unless your cluster needs two.\n\n### Environment\n\n- Scratchpad root: `SB=<SCRATCHPAD>`\n- **Prebuilt shared venv (READ-ONLY — never install into it):** `$SB/envs/<SHARED_VENV>` has\n  `reflex==<VERSION>` and the alpha sub-packages. Use `$SB/envs/<SHARED_VENV>/bin/reflex` directly.\n- Need other deps or versions? Make your OWN venv:\n  ```\n  uv venv $SB/envs/<yours> --python 3.11\n  uv pip install --python $SB/envs/<yours>/bin/python --prerelease=allow 'reflex==<VERSION>' <extras>\n  ```\n  Always pass `--prerelease=allow` for alphas; PyPI is the default index — never point it at the\n  checkout. Python 3.12/3.13/3.14 are available via `uv venv --python 3.14` etc.\n- **Playwright driver venv:** `$SB/envs/driver/bin/python` (playwright, httpx, websockets).\n  Chromium: `/opt/pw-browsers/chromium` — launch with\n  `p.chromium.launch(executable_path=\"/opt/pw-browsers/chromium\")`.\n  A ready-made driver with console/network capture is at\n  `.claude/skills/prerelease-test/scripts/drive_app.py` in the checkout (read-only use is fine).\n- **Local HTTP needs proxy bypass on the CLIENT side only:** prefix curl/Playwright commands with\n  `NO_PROXY=localhost,127.0.0.1 no_proxy=localhost,127.0.0.1` (curl: `--noproxy '*'`).\n  Do NOT export those variables into the reflex server's environment — it breaks bun's package\n  installs through the proxy, which looks like a framework bug and is not.\n- Set `REFLEX_TELEMETRY_ENABLED=false` for every reflex command.\n- Node and bun are preinstalled. Enterprise apps need `CI=true` to bypass the dev login gate.\n- App working dirs: `$SB/apps/<cluster>/...`. Run servers on YOUR ASSIGNED PORTS:\n  `reflex run --frontend-port <FP> --backend-port <BP>`. The first run does a bun install (1–2 min);\n  poll the frontend URL until it returns 200 for up to ~6 minutes before concluding failure.\n- `--loglevel debug` gives verbose server logs; redirect to a file and actually read it.\n\n### What \"testing\" means here\n\n- Real-world exploration, not coverage filling. Combine the feature with State vars,\n  `rx._x.client_state`, `@rx.memo` wrapping, `rx.ComponentState`, `rx.foreach`/`rx.cond`, event\n  chains (`yield Other.handler()`), background tasks, multiple pages and navigation — whatever\n  plausibly interacts. The original PR already tested the happy path.\n- Drive the app in Chromium as a user would: click, type, navigate, upload, drag, use the keyboard.\n- On EVERY run capture and inspect: (a) the server log file, (b) browser console messages (errors\n  AND warnings), (c) failed requests / 4xx-5xx responses, (d) screenshots at key moments.\n- Baseline comparisons are what make findings actionable: if behavior looks wrong, check the\n  previous stable (`uv pip install 'reflex==<PREV_STABLE>'` in its own venv). Only-on-new is a\n  regression and high severity; both-versions is context worth noting, not a blocker.\n- Prod matters too: `reflex run --env prod` compiles and serves the built frontend. Test both modes\n  when your feature could differ (hydration, memoization, routing, prerender).\n\n### Known-benign noise — do not report these as findings\n\n- Browser console: the React Router \"💿 Hey developer\" HydrateFallback log, vite\n  `connecting.../connected` debug lines, the React DevTools download info line.\n- `reflex init` logging a few \"Failed to connect to https://registry.npmmirror.com\" lines before\n  falling back (this environment blocks that mirror). Do report it if the fallback itself fails.\n- Transient bun \"incorrect peer dependency\" warnings during a one-time upgrade migration, provided\n  the final lockfile is consistent.\n\nIf you see something surprising that is not on this list, investigate it — several real findings\nhave surfaced first as an unexplained warning.\n\n### Deliverables (mandatory)\n\n1. Copy reusable artifacts into the repo (plain `cp`/`rsync`, no git):\n   `DEST=<ARTIFACT_ROOT>/<cluster>/`\n   - the app source dirs, EXCLUDING `.web/`, `node_modules/`, `.states/`, `assets/external/`,\n     `*.db`, venvs\n   - your Playwright/repro scripts\n   - `NOTES.md`: what you tested, how to rerun it (exact commands), what you observed, including\n     benign quirks\n2. Return structured findings: every discrete check as a test entry (pass/fail/anomaly/skipped)\n   with enough repro detail that another agent can reproduce a failure from `NOTES.md` and your\n   scripts alone, without your conversation. An \"anomaly\" is anything surprising (console error,\n   warning, traceback, visual glitch, perf cliff) even when functionality works.\n\n### Timeboxing\n\nBe thorough but keep moving: if one sub-test resists debugging for ~10 minutes, record it as an\nanomaly with logs attached and continue. Finishing the whole cluster beats perfecting one test.\n\n<!-- File: .claude/skills/prerelease-test/references/clusters.md (Tokens: ~970 | Category: anthropic-skill) -->\n# Cutting the changelog into clusters\n\nA cluster is one agent's assignment: a group of changelog entries that share a subsystem, so the\nagent can build one or two apps that exercise all of them together and notice how they interact.\n\n## How to cut them\n\nGroup by **where the change lives at runtime**, not by which PR shipped it. Entries that touch the\nsame subsystem belong together even when they came from unrelated PRs, because the interesting\nbugs are in their interaction — and one app can cover them all.\n\nAim for 8–12 clusters of 2–6 changelog entries each. A cluster that needs more than two apps is\ntoo big; one with a single trivial entry should be folded into a neighbour.\n\nEach cluster brief should carry:\n- the changelog lines verbatim (agents should not have to re-derive what shipped),\n- the PR numbers, so the agent can read intent,\n- concrete \"combine it with\" suggestions — this is what turns a checklist into exploration,\n- anything the entry implies but does not state (a perf claim to measure, a behavior that should\n  differ between dev and prod).\n\n## Standing coverage checklist\n\nMost Reflex releases touch some subset of these. Use it to check you have not left a shipped change\nunassigned, and as a source of interaction ideas.\n\n| Area | What to build | Interactions worth forcing |\n|---|---|---|\n| Routing / navigation | Multi-page app with dynamic (`[id]`), catchall (`[[...splat]]`) and static-sibling routes; slow `on_load` | Navigate away mid-`on_load`; two tabs on different dynamic values; browser back/forward; direct load vs client-side nav; prod mode |\n| State & event loop | Counter hammered by clicks while a background task writes | Background task + foreground handler racing; `yield`-streaming handlers; `async with self`; abrupt disconnect mid-stream |\n| Components / props | One page per changed component | Prop bound to a State var, to a `client_state` var, and inside `@rx.memo`; explicit `style=` merged with forwarded props |\n| Memoization | `@rx.memo` component with state-bound props and an event-handler prop, plus render counters | Memo in `rx.foreach`; memo wrapping `ComponentState`; two memos sharing a name in different modules; dev vs prod |\n| Typing / annotations | State vars using every annotation shape the entry mentions | Assign at runtime (not just compile); pass the handler *uncalled* to a trigger; run on the oldest and newest supported Python |\n| Uploads | `rx.upload` with buffered and streamed handlers | Hostile filenames (traversal, unicode, all-dots, spaces); raw multipart via httpx alongside browser uploads |\n| Logging / CLI | Run every CLI verb with and without the logging flags | Strict JSON-lines parsing of stdout; a user app that configures `logging` itself; missing optional sub-packages |\n| Config / plugins | App with the config knob set, unset, and set via env var | Deprecated form alongside the new form; plugin explicitly enabled vs implicit |\n| Build / prod / export | Multi-page app through `run --env prod`, `export`, `run --env preview` | Serve exported frontend statically with a backend-only server; inspect generated `.web/package.json`; custom component with a changed library |\n| Registration / multi-app | Two apps in one process; `AppHarness` twice | Sequential and simultaneous; check for registration leakage between them |\n| Optional dependencies | Bare install, each extra, and the upgrade path | Import the optional package's feature without the extra and judge the error message quality |\n| DevTools / perf | App with nested substates, custom components, client-only wrappers | Walk React fibers for `displayName`; record navigation main-thread cost; verify perf claims rather than trusting them |\n\n## Downstream and packaging clusters\n\nTwo clusters that are not feature-shaped but catch the highest-severity problems:\n\n- **Breaking-change surface.** For every entry under \"Breaking Changes\" (and every removal you spot\n  in the diff), ask what a downstream caller sees. Grep the published `reflex-enterprise` wheel and\n  the popular third-party packages (`reflex-local-auth`, `reflex-global-hotkey`) for the removed\n  names. A bare `AttributeError`/`ImportError` with no pointer to the replacement is a finding even\n  when the removal itself was intended.\n- **Packaging.** `.claude/skills/prerelease-test/scripts/audit_pyi.py`, plus a check that each package's declared dependency pins\n  match what the changelog says and that installing from the sdist works.\n\n<!-- File: .claude/skills/prerelease-test/references/orchestration.md (Tokens: ~1671 | Category: anthropic-skill) -->\n# Orchestrating the fleet\n\n## Choosing the mechanism\n\nInvoking this skill is itself the opt-in for the Workflow tool, so a full campaign should use it —\nthe explore→verify pipeline is deterministic control flow over many agents, exactly what Workflow\nis for. For a quick check or a single cluster, plain `Agent` calls are simpler and cheaper.\n\nUse one workflow per phase rather than one giant script. Phase results change what you want to ask\nnext (a cluster that finds a breaking change reshapes the enterprise phase), and you stay in the\nloop between phases.\n\n## The explore → verify pipeline\n\nThe shape that matters: each cluster's findings go straight into verification without waiting for\nthe other clusters. Use `pipeline`, not a barrier — a slow cluster should not hold up verification\nof a fast one.\n\n```js\nexport const meta = {\n  name: 'prerelease-explore',\n  description: 'Exercise <version> feature clusters end-to-end, then adversarially verify findings',\n  phases: [{ title: 'Explore' }, { title: 'Verify' }],\n}\n\nconst SB = '<scratchpad>'\nconst DEST = '<artifact root>'\n\nconst FINDINGS_SCHEMA = {\n  type: 'object',\n  required: ['cluster', 'summary', 'tests', 'issues', 'artifacts_dir'],\n  properties: {\n    cluster: { type: 'string' },\n    summary: { type: 'string' },\n    tests: {\n      type: 'array',\n      items: {\n        type: 'object',\n        required: ['name', 'status', 'details'],\n        properties: {\n          name: { type: 'string' },\n          status: { type: 'string', enum: ['pass', 'fail', 'anomaly', 'skipped'] },\n          details: { type: 'string' },\n          repro: { type: 'string' },\n        },\n      },\n    },\n    issues: {\n      type: 'array',\n      items: {\n        type: 'object',\n        required: ['title', 'severity', 'repro'],\n        properties: {\n          title: { type: 'string' },\n          severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low'] },\n          repro: { type: 'string' },\n          evidence: { type: 'string' },\n          regression: { type: 'boolean', description: 'true if the previous stable behaves correctly' },\n        },\n      },\n    },\n    artifacts_dir: { type: 'string' },\n  },\n}\n\nconst VERDICT_SCHEMA = {\n  type: 'object',\n  required: ['confirmed', 'notes'],\n  properties: {\n    confirmed: { type: 'boolean' },\n    notes: { type: 'string' },\n    root_cause_guess: { type: 'string' },\n  },\n}\n\nphase('Explore')\nconst results = await pipeline(\n  CLUSTERS,\n  (c, _item, i) => agent(brief(c, i), { label: `explore:${c.key}`, phase: 'Explore', schema: FINDINGS_SCHEMA }),\n  async (res, c, i) => {\n    if (!res) return { cluster: c.key, agent_died: true }\n    // Cap the fan-out per cluster. Issues past the cap are absent from verified_issues but\n    // still present in res.issues, which is how the report tells them from verified ones.\n    const issues = (res.issues || []).slice(0, 4)\n    if (!issues.length) return res\n    const verdicts = await parallel(\n      issues.map((iss, j) => () =>\n        agent(verifyBrief(c, iss, j), { label: `verify:${c.key}:${j}`, phase: 'Verify', schema: VERDICT_SCHEMA })\n          // A dead verifier resolves falsy. Give it its own marker: `verdict: null` would\n          // read as a verdict that cleared the issue, and dropping the entry would leave a\n          // hole indistinguishable from an issue the cap never sent to a verifier.\n          .then((v) => (v ? { issue: iss, verdict: v } : { issue: iss, verifier_died: true })),\n      ),\n    )\n    return { ...res, verified_issues: verdicts }\n  },\n)\n// Dead explorers stay in as `agent_died` markers rather than being filtered out: a cluster\n// that produced nothing is a hole in the campaign, and silently dropping it is how a hole\n// gets mistaken for a clean result. Same for `verifier_died` above. Every marker is work\n// the campaign did not do, so the report must account for each one rather than skip it.\nreturn results.filter(Boolean)\n```\n\nThe verifier's prompt is what makes this work. It must:\n- reproduce **from the written repro alone**, in its own working directory, not by reading the\n  reporter's conversation — that is simultaneously a test of the repro's quality,\n- be told to actively **refute**: is this an environment quirk, an API misuse, pre-existing on the\n  previous stable, or a genuine defect?\n- set `confirmed: true` only for a genuine defect a fix agent should act on,\n- append a `## VERIFICATION` section to the cluster's `NOTES.md` so the record travels with the\n  artifacts.\n\n## Port map\n\nGive every agent a disjoint range and tell it to always pass `--frontend-port/--backend-port`\nexplicitly. Never let anything use the defaults (3000/8000) — that is how two agents collide and\nproduce confusing, unreproducible results.\n\n| Stage | Frontend | Backend |\n|---|---|---|\n| Explore agent *i* | `3100 + 40i` … +19 | `8100 + 40i` … +19 |\n| Verify agent *i.j* | `3600 + 40i + 4j` … +3 | `8600 + 40i + 4j` … +3 |\n| Orchestrator smoke | 3050–3059 | 8050–8059 |\n\n## Prompt scaffolding for each agent\n\nEvery cluster prompt should open with the same preamble, then the cluster-specific brief:\n\n```\nFIRST read <SB>/AGENT_BRIEF.md and follow every rule in it (isolated PyPI-only installs — never\ninstall from the checkout; end-to-end browser testing; artifact + NOTES.md deliverables; kill your\nprocesses).\nYour cluster key: \"<key>\". Working dir: <SB>/apps/<key>/. Artifact destination: <DEST>/<key>/.\nYour RESERVED ports: frontend <FP_START>-<FP_END>, backend <BP_START>-<BP_END> — always pass them\nexplicitly, and never bind outside them.\n<cluster brief: changelog lines verbatim, PR numbers, combine-with suggestions>\nAlso in scope: anything adjacent you notice (log warnings, console anomalies, network errors,\nvisual glitches). Record benign-but-surprising observations in NOTES.md and as 'anomaly' entries.\n```\n\nFill the port ends from the table above, not from a fixed span: an explore agent's range is 20\nports wide and a verify agent's is 4. A verifier told it owns 20 would reach into the next\nverifier's range, which is the collision the map exists to prevent.\n\n## Running it\n\n- Two agents at a time is right for a 4-CPU box; the workflow's own concurrency cap handles the\n  rest of the queue.\n- Between phases, read the results before launching the next one.\n- Schedule a check-in (`send_later`, ~45 min) during long runs so a wedged agent or a leaked dev\n  server gets noticed. Check `ps` for stray `reflex run` processes and commit finished clusters.\n- When the workflow completes, its full structured result is in the task output file; parse it for\n  the report rather than re-reading transcripts.\n\n<!-- File: .claude/skills/prerelease-test/references/reporting.md (Tokens: ~1061 | Category: anthropic-skill) -->\n# Reporting\n\n## FINDINGS.md\n\nThe audience is a maintainer deciding what blocks the release, and fix agents who will get handed\none finding and nothing else. Write for both: a summary that supports a go/no-go call, and findings\nself-contained enough to act on in isolation.\n\n```markdown\n# Findings — reflex <version> pre-release testing (<date>)\n\n<One paragraph on method: PyPI-only isolated venvs, end-to-end browser runs, previous-stable\nbaselines, independent adversarial verification of every claimed issue. Agent count.>\n\n## Versions under test\n<Every package and version, noting which are new in this train and that each is published.>\n<Environment: OS, CPU/RAM, node/bun, python versions, browser.>\n\n## Executive summary\n<What works — name the headline changelog items verified.>\n<What blocks — the short list, with severity.>\n<Severity histogram, and the count of refuted claims.>\n\nIndex:\n- FINDING-001: <title> (SEVERITY)\n- ...\n\n## FINDING-00N: <title> (SEVERITY)\n\n- Cluster: `<cluster>` | Regression vs <prev stable>: yes/no | Verifier: CONFIRMED\n- Repro: <exact commands/steps, self-contained>\n- Evidence: <log excerpt, console error, screenshot path>\n- Root cause (verifier analysis): <file:line and mechanism, when known>\n- Verification notes: <what the independent reproducer found>\n\n## Refuted / reclassified claims\n- **<title>** (`<cluster>`): <why it is not an actionable defect for this release>\n\n## Cluster summaries\n### `<cluster>` (pass:N, anomaly:N, fail:N)\n<2-4 sentences: what was built, what was verified, what was found.>\n```\n\nTwo things carry disproportionate weight and are easy to skip:\n\n- **The refuted list.** It shows the findings were filtered, which is why a maintainer can trust the\n  ones that remain. Never quietly drop a refuted claim.\n- **Regression status on every finding.** \"Broken in both versions\" and \"newly broken\" lead to\n  opposite decisions, and the reader cannot recover that from the description.\n\n## RELEASE_PLAN.md\n\n```markdown\n# Release plan — what blocks <version> vs what gets filed\n\n## Already in flight\n| PR | Covers | Gap check |\n<For each open PR, which findings it addresses and — importantly — what it does NOT cover.>\n\n## Fix before release\n### Security\n### Confirmed regressions\n### High impact and/or trivially small\n<Each item: finding ref, one-line rationale tied to the rubric, and the shape of the fix.>\n\n## File as issues, fix after release\n### <this repo>\n### <downstream repo>\n\n## Decisions needed from a maintainer\n<Behavior changes that are either bugs or missing changelog entries — their call, not yours.>\n\n## Suggested sequencing\n<Order of PRs, noting which can land in parallel and which touch the same files.>\n```\n\nThe rubric (confirmed regression / security / significant-impact-or-trivial) is in `SKILL.md`.\nApply it visibly: each entry should say which arm of the rubric put it there, so the maintainer can\ndisagree with a specific judgment rather than the whole list.\n\n## Filing issues\n\nFor post-release items: search for duplicates first (2–3 keyword variants, open *and* closed), then\nfile with a self-contained repro, observed vs expected, environment, a note that it came from\n`<version>` pre-release testing, and a pointer to the artifacts branch and cluster directory.\nMirror `.github/ISSUE_TEMPLATE/bug_report.md` where it fits.\n\n## If the user asks for the fixes afterwards\n\nThat is a separate engagement. What worked well:\n\n- **One PR per finding**, branched from current `main`, in its own git worktree so parallel fix\n  agents never collide.\n- **Regression test first**: write it, show it failing against unfixed `main`, then fix, then show\n  it passing. Report both states in the PR body — a reviewer should not have to take it on faith.\n- **News fragment** under the right package's `news/` directory. The changelog CI gate checks per\n  package: a fix touching `packages/reflex-base/` needs a fragment in\n  `packages/reflex-base/news/`, and a root-only fragment will fail the gate.\n- **Adversarial review of each PR** before handing it over: an independent agent re-runs the\n  regression test against unfixed source to confirm it actually pins the bug, and checks repo\n  conventions. This catches PRs whose test passes either way.\n- PR body: cite the FINDING number and that it came from pre-release testing, describe the defect\n  mechanism, the fix, and the test plan including the failing-before evidence.\n- Watch CI after opening (`subscribe_pr_activity`) and drive each PR to green.\n\n<!-- File: .claude/skills/prerelease-test/SKILL.md (Tokens: ~2693 | Category: anthropic-skill) -->\n---\nname: prerelease-test\ndescription: Run the independent pre-release QA campaign for a Reflex release train. Discovers what shipped by reading every CHANGELOG.md on the pre-release branch, checks each package actually published to PyPI, then exercises the new features end-to-end in real apps driven by a real browser using ONLY published packages, upgrade-tests reflex-examples apps from the previous stable, regression-tests reflex-enterprise demos, audits wheel/sdist packaging, and produces a triaged FINDINGS.md plus a fix-before-release plan. Use this whenever a Reflex release is being prepared or checked — the user mentions a pre-release, an alpha/beta/rc, an `r/pre-*` branch, \"about to release\", release QA, validating a release candidate, or re-verifying that release-blocking fixes landed in a newer alpha. Also use it for the narrower slices on their own: smoke-testing published packages, upgrade/regression testing example apps against a new version, or auditing that packages ship their `.pyi` stubs in both wheel and sdist.\n---\n\n# Reflex pre-release testing\n\nThis skill runs the QA campaign that stands between a pre-release and a release: independent,\nadversarial, end-to-end exercise of what actually got published, from the perspective of a user\nwho runs `pip install reflex` and opens a browser.\n\nIts value comes from three habits, not from breadth of assertions:\n\n1. **Only published packages.** Everything installs from PyPI into throwaway venvs. The checkout\n   has unreleased code, different metadata, and a different dependency graph — testing it tells\n   you nothing about what users will get, and a package that failed to publish is itself a\n   release blocker you would otherwise miss.\n2. **Baseline against the previous stable.** A defect that also reproduces on the last release is\n   a bug; one that only reproduces on the new version is a regression and usually a blocker.\n   Without the baseline run you cannot tell them apart, and the triage that follows is guesswork.\n3. **Adversarially verify before reporting.** Have a second agent reproduce each claimed issue\n   from the written repro alone and actively try to refute it. In practice this refutes or\n   reclassifies a meaningful share of findings — and it is what makes the report trustworthy\n   enough for maintainers to act on directly.\n\n## Deliverables\n\nProduce these under `prerelease-testing/<date>-<version>/` in the repo and commit them to a work\nbranch as you go (never to `main`):\n\n- `FINDINGS.md` — executive summary, numbered findings with repro + evidence + regression status,\n  refuted claims, and per-cluster summaries. Templates: `references/reporting.md`.\n- `RELEASE_PLAN.md` — triage into fix-before-release vs file-as-issue. Rubric below.\n- One directory per test cluster containing the sample app sources (no `.web/`, `node_modules/`,\n  venvs), the driver scripts, `NOTES.md` with exact rerun commands, logs and screenshots.\n- `README.md` — what each cluster covers and how to reuse it for the next release.\n\nFindings must be reproducible by a stranger from `NOTES.md` alone. That is the bar: a fix agent\ngets handed the finding and nothing else.\n\n## Phases\n\nWork these in order. Phases 2–5 can overlap; 0 and 1 gate everything.\n\n### Phase 0 — Scope discovery\n\nFind the pre-release branch (`git ls-remote --heads origin 'r/pre-*'`, or the user names it), then\nread **every** `CHANGELOG.md` on it: the root one plus `packages/*/CHANGELOG.md`. The top entry of\neach is what this train ships.\n\nRun the discovery script to extract every package's version and confirm each is published:\n\n    uv run --script .claude/skills/prerelease-test/scripts/check_release_versions.py --ref <git-ref>\n\n(Script paths in this skill are repo-root-relative — the repo has its own unrelated `scripts/`\ndirectory, so the prefix matters.) It exits 1 when a package is confirmed missing and 2 when a\ncheck could not complete, so a proxy hiccup never reads as a missing package. An unpublished\nversion is a finding in its own right — report it immediately rather than working around it.\n\nRead the linked PRs for anything whose intent is not obvious from the changelog line; the GitHub\nMCP tools (`mcp__github__pull_request_read`) do this well. Understanding what a change was *for*\nis what lets you test it as a user rather than as a checklist.\n\n### Phase 1 — De-risk with a smoke test\n\nBefore any fan-out: one venv, `reflex init --template blank`, `reflex run`, then drive it in\nChromium with `.claude/skills/prerelease-test/scripts/drive_app.py`. This shakes out environment\nproblems (proxy, bun installs, browser path) once, in a context where you can debug them, instead\nof inside ten parallel agents.\n\nThe scripts carry PEP 723 metadata, so `uv run --script <path>` runs each one in its own isolated\nenvironment (the driver pulls in playwright that way); running them with an existing driver venv's\ninterpreter works too.\n\nAlso confirm the dependency graph resolves the way the changelog says it should (e.g. optional\ndependencies genuinely absent, sub-packages pinned as intended).\n\n### Phase 2 — Feature exploration fan-out\n\nDecompose the changelog into clusters of related changes and give each to its own agent, with an\nadversarial verification stage behind it. See `references/clusters.md` for how to cut the clusters\nand a standing coverage list; `references/orchestration.md` for the Workflow script, schemas and\nport map.\n\nThe instruction that makes this productive: **real-world exploration, not coverage filling.**\nCombine each new feature with the things users actually combine it with — State vars,\n`rx._x.client_state`, `rx.ComponentState`, `@rx.memo` wrapping, `rx.foreach`/`rx.cond`, event\nchains, background tasks, multiple pages and navigation, dev *and* prod mode. Bugs live in the\ninteractions, and the original PR's tests already cover the happy path.\n\nEvery run inspects all four channels: server log, browser console (errors *and* warnings), network\ntab (failed requests, 4xx/5xx), and the rendered page. Findings frequently show up in a channel\nnobody asserted on.\n\n### Phase 3 — Upgrade regression\n\nUsers upgrade in place; that path has its own failure modes (lockfile migration, pruned packages,\nstale `.web/`). Clone `reflex-dev/reflex-examples`, pick apps that span the feature surface —\nincluding ones using third-party packages (`reflex-local-auth`, `reflex-global-hotkey`) and\n`reflex[db]`/API apps — then for each:\n\n1. Install the **previous stable** (no `--prerelease` flag, so requirements resolve as a user's\n   would), run it, and drive its real user flows in the browser. This is your baseline.\n2. Upgrade the *same* venv and *same* app directory in place to the new version, preserving\n   `.web/` and `reflex.lock/`. Watch the first run's log closely — that is where migration\n   happens. Re-drive the identical flows and compare.\n3. Do one cold run (`rm -rf .web`) to check the fresh-install path converges to the same state.\n\nDiff `.web/package.json` before and after; unexpected dependency changes are findings.\n\n### Phase 4 — Enterprise regression\n\nDownstream breakage is the most common release blocker, because removing a public name is\ninvisible until something imports it. Install the **published** `reflex-enterprise` (never the\ncheckout) against the new reflex and run its demos — ag-grid, map, dnd, mantine, flow, the MCP\nplugin, OIDC. Baseline against the previous stable whenever something fails, so you can say\nwhether the new release broke it.\n\nBefore running anything, grep the published enterprise wheel for names the changelog says moved or\nwere removed; that finds the breakage in seconds instead of hours.\n\n### Phase 5 — Packaging audit\n\nAudit every package in the train; the discovery script feeds it the whole list. Chain the two with\n`&&`, never a pipe — a pipe reports only the audit's exit status, so a package whose PyPI check\nnever completed would be dropped from the list and the audit would still print PASS over what was\nleft. The `&&` is what makes that impossible: the audit runs only when discovery exits 0.\n\n    uv run --script .claude/skills/prerelease-test/scripts/check_release_versions.py \\\n      --ref <ref> --specs > specs.txt \\\n      && xargs uv run --script .claude/skills/prerelease-test/scripts/audit_pyi.py \\\n        --manifest-ref <ref> < specs.txt\n\nIt verifies each package ships its own generated `.pyi` stubs in **both** wheel and sdist, that\nthey are byte-identical between the two, that no package leaks another package's stubs, and that\ncounts line up with `pyi_hashes.json` (a package absent from the manifest must ship none).\n\nStub content hashes legitimately differ from the committed manifest because the build hook\nregenerates them at release time — compare *presence and counts*, and wheel against sdist.\n\n### Phase 6 — Triage and report\n\nWrite `FINDINGS.md` first (everything confirmed), then `RELEASE_PLAN.md` splitting findings into:\n\n**Fix before release** — anything meeting one of:\n- a confirmed regression against the previous stable,\n- security-relevant (path traversal, unauthenticated input handling, injection),\n- significant user impact, or trivially small to fix (a one-line guard, a missing default).\n\n**File as issues, fix after** — everything else, including pre-existing defects the campaign\nhappened to surface. Downstream (enterprise) issues go to that project's tracker, not this repo's.\n\nAlso flag decisions only a maintainer can make — an undocumented behavior change is either a bug\nor a missing changelog entry, and which one it is is their call. Ask rather than assume.\n\n### Phase 7 — Re-verify the next build\n\nWhen a new alpha ships with the fixes, re-run the *original failing repro* for each finding\n(not just the unit tests) against the new published packages, plus a general smoke. Append the\npass/fail table to `FINDINGS.md`. When the final ships, do one last stock-install smoke:\n`pip install reflex==<final>` with no prerelease flag, init, run, browser, and confirm the\nresolved graph is all-final.\n\n## Working rules\n\n- **Isolation.** Every agent gets its own venv and its own reserved port range; never install into\n  a shared venv. See the port map in `references/orchestration.md`.\n- **The traps are real.** `references/agent-brief.md` is the brief to hand every agent — it carries\n  the environment gotchas (checkout shadowing, proxy variables breaking installs) and the list of\n  known-benign console noise. Agents that skip it rediscover the same problems and report noise as\n  findings.\n- **Concurrency.** Dev servers are heavy (bun + vite + granian). On a 4-CPU box run about two\n  agents at a time and one dev server per agent; more just makes everything slow and flaky.\n- **Commit as you go.** Each cluster's artifacts land on the work branch when that cluster\n  finishes, so a long campaign is never one unrecoverable batch.\n- **Never fix framework code during the campaign.** Testing and fixing are separate engagements\n  with separate review standards; mixing them costs you the independence that makes the findings\n  credible. Record the repro and move on. (If the user then asks for fixes, that is a new task —\n  one PR per finding, regression test first, `references/reporting.md` has the PR conventions.)\n\n## Scaling the campaign\n\nFull campaign is roughly 30 agents over several hours. Scale down by dropping whole phases rather\nthan by testing each phase more shallowly — a shallow pass produces false confidence:\n\n- **Quick check** (~30 min): phases 0, 1, 5, plus grep-based downstream checks from phase 4.\n- **Standard** (~2 h): add phase 2 over the three or four highest-risk clusters.\n- **Full**: everything, with adversarial verification on every claimed issue.\n\nAsk the user which they want if the request is ambiguous and the difference matters.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/airtable.md (Tokens: ~384 | Category: anthropic-skill) -->\n---\ntags: Data Infrastructure\ndescription: Connect your apps to Airtable to read, create, and update records in real time.\n---\n# Airtable Integration\n\nThe **Airtable Integration** lets your apps interact with Airtable bases to **store, fetch, and update structured data** directly from workflows, user actions, or automated triggers. Perfect for managing dynamic content, customer data, or workflows without complex backend setup.\n\n\n## What You Can Do\n\nWith the Airtable Integration, your app can:\n\n* Read and display data from Airtable bases\n* Create new records dynamically from user actions\n* Update or delete records through workflows\n* Power AI experiences with live database content\n* Sync structured data without hosting your own database\n\n## Step 1: Get Your Airtable API Key\n\n1. Go to [Airtable](https://airtable.com/).\n2. Log in or create a free account.\n3. Navigate to [**Developer Hub**](https://airtable.com/create/tokens) from your account menu.\n4. Under **Personal access tokens**, click **Create token**.\n5. Add the appropriate scopes (e.g. `data.records:read` and `data.records:write`).\n6. Copy your API token.\n   * Example: `patxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n\n1. Click the **Settings** gear icon and navigate to the **Integrations** tab.\n2. Find and enable the **Airtable** integration.\n3. Paste your **API Key** in the input field.\n4. Click **Connect** to confirm the connection.\n\n## Step 3: Use in Your Workflows\n\nOnce connected, you can use Airtable actions in your app to:\n\n* Fetch records to display dynamic lists\n* Add user submissions as new rows\n* Update status fields or metrics from AI workflows\n\nand more.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/anthropic.md (Tokens: ~327 | Category: anthropic-skill) -->\n---\ntags: AI\ndescription: Connect your apps to Anthropic's Claude models for advanced AI capabilities.\n---\n# Anthropic Integration\n\nThe **Anthropic Integration** allows your app to use [Anthropic’s Claude models](https://www.anthropic.com/claude) for tasks such as text generation, summarization, reasoning, and other advanced AI capabilities. Once connected, you can call Claude directly from your workflows, UI actions, or automated triggers.\n\n\n## Step 1: Obtain an Anthropic API Key\n\n1. Go to the [Anthropic Console](https://console.anthropic.com/).\n2. Navigate to **API Keys** in your account settings.\n3. Click **Create Key** and give it a descriptive name (e.g., “AI Builder”).\n4. Copy the generated key.\n\n   * **Example:** `sk-ant-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Anthropic** in your app settings.\n2. Paste your **Anthropic API Key** in the input field.\n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Claude for AI-powered features across workflows and components.\n\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Anthropic API key in public code repositories.\n* **Use environment-specific keys:** Separate dev, staging, and production keys help manage access and security.\n* **Secure API access:** The key allows your app to interact with Anthropic endpoints securely and efficiently.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/aws.md (Tokens: ~1300 | Category: anthropic-skill) -->\n---\ntags: Data Infrastructure\ndescription: Connect to Amazon Web Services (AWS) for cloud storage, databases, compute, AI/ML, and more.\n---\n# AWS Integration\n\nThe **AWS Integration** allows your app to connect to [Amazon Web Services (AWS)](https://aws.amazon.com/) — the world's most comprehensive cloud platform. Once connected, your app can access 200+ AWS services including storage, databases, compute, AI/ML, and more using the boto3 SDK.\n\n## What You Can Do\n\nWith AWS integration, your app can:\n- **S3 (Object Storage):** Upload, download, and manage files in S3 buckets. Generate presigned URLs for secure file access. Works with S3-compatible services like MinIO, Cloudflare R2, and DigitalOcean Spaces.\n- **DynamoDB (NoSQL Database):** Store and query data in a fully managed, serverless NoSQL database with single-digit millisecond performance.\n- **Lambda (Serverless Functions):** Invoke serverless functions, run code without managing servers, and build event-driven applications.\n- **SES (Email Service):** Send transactional emails, marketing emails, and notifications with high deliverability.\n- **SNS (Notifications):** Send push notifications, SMS, and email messages to users across multiple channels.\n- **SQS (Message Queues):** Build distributed, decoupled systems with reliable message queuing.\n- **Rekognition (Computer Vision):** Analyze images and videos for object detection, facial analysis, text extraction, and content moderation.\n- **Comprehend (NLP):** Extract insights from text using natural language processing for sentiment analysis, entity recognition, and topic modeling.\n- **Bedrock (AI Models):** Access foundation models from AI21 Labs, Anthropic, Cohere, Meta, Stability AI, and Amazon for generative AI applications.\n- **And 200+ more services:** EC2, RDS, CloudWatch, Polly, Textract, Translate, and many others.\n\n## Step 1: Obtain AWS Credentials\n\n1. Log in to the [AWS Console](https://console.aws.amazon.com/).\n\n2. **Create IAM credentials:**\n   - Navigate to **IAM (Identity and Access Management)**.\n   - Click **Users** → **Add user** or select an existing user.\n   - Attach policies based on the AWS services you plan to use:\n     - **S3:** `AmazonS3FullAccess` or custom S3 policy\n     - **DynamoDB:** `AmazonDynamoDBFullAccess` or custom DynamoDB policy\n     - **Lambda:** `AWSLambdaFullAccess` or custom Lambda policy\n     - **SES:** `AmazonSESFullAccess` or custom SES policy\n     - **Multiple services:** Attach multiple policies or create a custom policy combining permissions\n\n   **Example custom policy for S3 + DynamoDB:**\n   ```json\n   {\n     \"Version\": \"2012-10-17\",\n     \"Statement\": [\n       {\n         \"Effect\": \"Allow\",\n         \"Action\": [\n           \"s3:PutObject\", \"s3:GetObject\", \"s3:DeleteObject\", \"s3:ListBucket\",\n           \"dynamodb:PutItem\", \"dynamodb:GetItem\", \"dynamodb:Query\", \"dynamodb:Scan\"\n         ],\n         \"Resource\": [\n           \"arn:aws:s3:::YOUR_BUCKET_NAME/*\",\n           \"arn:aws:dynamodb:YOUR_REGION:YOUR_ACCOUNT_ID:table/*\"\n         ]\n       }\n     ]\n   }\n   ```\n\n3. **Generate access keys:**\n   - Under **Security credentials**, click **Create access key**.\n   - Choose **Application running outside AWS** as the use case.\n   - Copy your **Access Key ID** and **Secret Access Key**.\n\n   **Example credentials:**\n   * **Access Key ID:** `AKIAIOSFODNN7EXAMPLE`\n   * **Secret Access Key:** `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add AWS** in your app settings.\n2. Enter your **AWS Access Key ID** and **AWS Secret Access Key**.\n3. **(Optional)** Select your **AWS Region** (e.g., `us-east-1`, `eu-west-1`). Defaults to `us-east-1`.\n4. **(Optional)** Enter an **AWS Endpoint URL** if using S3-compatible services:\n   - **MinIO:** `http://localhost:9000` or your MinIO server URL\n   - **Cloudflare R2:** `https://<account-id>.r2.cloudflarestorage.com`\n   - **DigitalOcean Spaces:** `https://<region>.digitaloceanspaces.com`\n   - Leave blank for standard AWS services.\n5. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can access AWS services using boto3.\n\n## Important Notes\n\n* **IAM permissions:** Ensure your IAM user has the necessary permissions for the AWS services you plan to use. Attach service-specific policies (e.g., `AmazonS3FullAccess`, `AmazonDynamoDBFullAccess`, `AWSLambdaFullAccess`) or create custom policies with least-privilege access.\n* **AWS Region:** Most AWS services are region-specific. Select the correct region where your resources are located (e.g., S3 buckets, DynamoDB tables, Lambda functions).\n* **Cost management:** Monitor AWS usage and costs through the AWS Billing Dashboard. Set up billing alerts to avoid unexpected charges.\n* **Security:** Rotate your access keys regularly and enable MFA for AWS console access. Apply least-privilege IAM policies to limit permissions to only what's needed.\n* **S3-compatible services:** For S3 operations, this integration works with S3-compatible storage like MinIO (self-hosted), Cloudflare R2 (zero egress fees), and DigitalOcean Spaces. Just provide the custom endpoint URL in the configuration.\n* **Service availability:** Not all AWS services are available in all regions. Check the [AWS Regional Services List](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/) for service availability.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/azure_auth.md (Tokens: ~498 | Category: anthropic-skill) -->\n---\ntags: Authentication\ndescription: Integrate Azure for secure authentication and access management within your application.\n---\n# Azure Auth Manager Integration\n\nThe **Azure Auth Manager Integration** allows your app to authenticate users through Microsoft Azure Active Directory (Azure AD). This integration provides secure OAuth 2.0 authentication and supports multi-tenant applications with customizable tenant access.\n\n## Step 1: Set Up Azure App Registration\n\nBefore connecting, you need to register your app in Azure Portal:\n\n1 - Go to [Azure Portal](https://portal.azure.com) → **App Registrations**\n\n2 - Click **New registration** as shown in the image below:\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_1.webp)\n\n3 - Register your app. Ensure that for the Redirect URI you select **Web** and enter the following URI that you find in the Azure Auth Manager integration settings in AI Builder:\n   ```\n   https://{your-sandbox}/authorization-code/callback\n   ```\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_2.webp)\n\n4 - On the next page get your `client_id` (`AZURE_CLIENT_ID`) and `tenant_id` (`AZURE_VALID_TENANT_IDS`) from the **Overview** tab.\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_3.webp)\n\n5 - Next click `Add a certificate or secret` and copy the generated secret value (`AZURE_CLIENT_SECRET`).\n\n![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_4.webp)\n\n\n## Step 2: Configure the Integration\n\n1. Go to the **Integrations** section in your app settings by clicking **`@`** and then clicking the **Integrations** tab at the top.\n2. Click **Add** next to Azure Auth Manager.\n3. Fill in the credential fields:\n   - Enter your Azure Client ID\n   - Enter your Azure Client Secret\n   - Enter valid tenant IDs (comma-separated for multiple tenants)\n4. Click **Connect** to save the integration.\n\nYour app can now authenticate users through Azure AD with secure OAuth 2.0 flow.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/cartesia.md (Tokens: ~353 | Category: anthropic-skill) -->\n---\ntags: AI\ndescription: Add Cartesia’s powerful text-to-speech capabilities for realistic, real-time voice output and audio experiences.\n---\n# Cartesia Integration\n\nThe **Cartesia Integration** allows your app to generate **high-quality, realistic speech from text** using Cartesia’s advanced voice models. Once connected, you can easily add real-time voice capabilities to workflows, user interactions, and automated experiences.\n\n\n## Step 1: Obtain a Cartesia API Key\n\n1. Go to the [Cartesia Console](https://www.cartesia.ai/).  \n2. Log in or create an account.  \n3. Navigate to **API Keys** in your account settings.  \n4. Click **New**, give it a descriptive name (e.g., “AI Builder”), and copy it.  \n   - Example: `sk_car_xxxxxxxxxxxxx`\n\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Open your app and go to **Integrations → Add Cartesia**.  \n2. Paste your **Cartesia API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.  \n\nOnce connected, your app can convert text to speech seamlessly in real time or through workflows.\n\n\n\n## Step 3: Notes\n\n- **Secure API Access:** Keep your Cartesia API key safe. Do not hardcode it in public code.  \n- **Environment isolation:** Use different keys for dev, staging, and production to ensure clean separation.  \n- **Low latency:** Cartesia supports real-time streaming for conversational experiences.  \n- **Usage management:** Monitor your Cartesia dashboard for quotas, billing, and usage insights.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/cohere.md (Tokens: ~351 | Category: anthropic-skill) -->\n---\ntags: AI\ndescription: Add Cohere’s language models for text generation, classification, retrieval, embeddings, and more.\n---\n# Cohere Integration\n\nThe **Cohere Integration** allows your app to use [Cohere’s](https://cohere.com) state-of-the-art language models for natural language understanding and generation. Once connected, your app can power search, summarization, embeddings, classification, and conversational AI features directly from workflows and triggers.\n\n\n## Step 1: Obtain a Cohere API Key\n\n1. Go to the [Cohere Dashboard](https://dashboard.cohere.com/).  \n2. Log in or create an account.  \n3. Navigate to **API Keys** in your account settings.  \n4. Click **Create Key**, give it a descriptive name (e.g., “AI Builder”), and copy the key.  \n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Cohere** in your app settings.  \n2. Paste your **Cohere API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.  \n\nOnce connected, your app can access Cohere’s endpoints for language tasks like embeddings, classification, chat, and more.\n\n\n## Step 3: Notes\n\n- **Secure API Access:** Keep your Cohere API key private — do not hardcode it in public repositories.  \n- **Environment separation:** Use different keys for development, staging, and production environments.  \n- **Performance:** Cohere’s models support fast inference for production-ready experiences.  \n- **Observability:** Use the Cohere dashboard to monitor usage, quotas, and request logs.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/database.md (Tokens: ~824 | Category: anthropic-skill) -->\n---\ntags: Data Infrastructure\ndescription: Connect Reflex Build apps to PostgreSQL, MySQL, MSSQL, or SQLite databases.\n---\n# Database Integration\n\nThe Database Integration connects Reflex Build apps to an existing SQL database. When you enable the connection for an app, Reflex Build can inspect its schema and use that structure while generating the app.\n\n## Supported Databases\n\n- **PostgreSQL**\n- **MySQL**\n- **MSSQL** (Microsoft SQL Server)\n- **SQLite**\n\n## Add a Database Integration\n\n1. Open **Integrations** from the project sidebar.\n2. Select **Add Integration**.\n3. Search for and select **Database**.\n4. Configure the connection using **Connection Details** or **Database URI**.\n5. Optionally enter an integration name to distinguish this connection from others in the project.\n6. Select **Save Changes**.\n\nThe integration is saved at the project level. Open an app's **Integrations** panel to enable it for that app when needed.\n\n## Connection Details\n\nUse **Connection Details** to enter each part of the connection separately.\n\nFor PostgreSQL, MySQL, and MSSQL, choose the database type and enter:\n\n- `hostname`: the database server address.\n- `port`: defaults to `5432` for PostgreSQL, `3306` for MySQL, or `1433` for MSSQL.\n- `username` and `password`: the database credentials.\n- `database_name`: the database to connect to.\n\nFor MSSQL, **Trust Server Certificate** skips certificate identity validation. Use it only as a temporary workaround for an untrusted or self-signed server certificate, and prefer configuring a certificate that the client trusts.\n\nFor SQLite, select **SQLite** and enter an HTTP or HTTPS **SQLite Download URL**. Reflex Build downloads the database file before using it.\n\n## Database URI\n\nUse **Database URI** when you have a complete connection URI for one of the supported database types. For example:\n\n```text\npostgresql://username:password@hostname:5432/database_name\n```\n\nEnter the URI in `db_url`, then select **Save Changes**. Reflex Build selects the database driver automatically. Include provider-required connection options as query parameters when needed.\n\n## Connect through an SSH Tunnel\n\nUse an SSH tunnel when the database is on a private network but can be reached through a bastion host. This option is available for PostgreSQL, MySQL, and MSSQL in both connection modes. It is not available for SQLite.\n\n1. Enter the database connection details or URI. Keep the database hostname and port set to the address the bastion host uses to reach the database.\n2. Turn on **Connect via SSH tunnel**.\n3. Enter the `ssh_hostname`, `ssh_port` (usually `22`), and `ssh_username` for the bastion host.\n4. Paste the corresponding PEM-formatted **SSH private key**.\n5. Select **Save Changes**.\n\nThe SSH account must allow port forwarding to the database host and port. Use a dedicated, restricted SSH key and database user for Reflex Build.\n\n```md alert warning\n# Keep credentials private\n\nEnter database passwords, connection URIs, and SSH private keys only in the integration form. Do not put them in prompts, knowledge, source code, or screenshots.\n```\n\n## Enable the Integration for an App\n\nOpen the app's **Integrations** panel and enable the saved database connection. Reflex Build then connects to the database and, when the app does not already have a model file, creates the app's data models from the schema.\n\nIf the connection fails, check that:\n\n- The database or bastion host is reachable.\n- The ports are open and the credentials are valid.\n- The database user can read the schema and has only the data permissions the app needs.\n- The SSH user can forward traffic to the database when tunneling is enabled.\n\n```md alert\n# NoSQL Databases\n\nUse the dedicated MongoDB integration when applicable. For another NoSQL database, add its Python SDK or configure a custom integration; the Database Integration supports SQL databases.\n```\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/databricks.md (Tokens: ~1414 | Category: anthropic-skill) -->\n---\ntags: Data Infrastructure\ndescription: Connect with Databricks to run data pipelines and advanced analytics seamlessly.\n---\n\n\n# Databricks Integration\n\nThe **Databricks Integration** allows your app to connect to [Databricks](https://www.databricks.com/) for secure data access, querying, and analytics. Once connected, you can run SQL queries, retrieve results, and power data-driven workflows directly from your app.\n\n## What You Can Do\n\nWith Databricks, your app can:\n- Connect securely to your Databricks workspace.  \n- Run **SQL queries** or fetch data programmatically.  \n- Build **dashboards and data visualizations** on top of your Databricks tables.  \n- Automate workflows triggered by new or updated data.  \n- Combine Databricks with AI models for advanced analytics.\n\n\n\n## Step 1: Get Your Databricks Credentials\n\n### 1 - Log in to your [Databricks Workspace](https://databricks.com/).\n\n### 2 - Get your **DATABRICKS_HOST** and **DATABRICKS_WAREHOUSE_ID**:\n\n   - Go to `SQL Warehouses` from the sidebar.\n   - Select your desired warehouse.\n   - Click `Connection details`.\n   - Copy the Server hostname (this is your **DATABRICKS_HOST**).\n   - Copy the HTTP path removing the `/sql/1.0/warehouses/` prefix (this is your **DATABRICKS_WAREHOUSE_ID**).\n\n![Databricks SQL Warehouse connection details](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_1.webp)\n\n### 3 - Get your **DATABRICKS_CATALOG** and **DATABRICKS_SCHEMA**:\n   - Click the SQL Editor from the sidebar.\n   - Choose the **DATABRICKS_CATALOG** and **DATABRICKS_SCHEMA** from the dropdowns as shown below.\n\n![Selecting Databricks catalog and schema in SQL Editor](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_4.webp)\n\n\n### 4 - Obtain your authentication credentials:\n\nThere are two methods to authenticate your app with Databricks: using interactive U2M **OAuth** or via registered M2M **Service Principal**. Choose one of the methods below to obtain the necessary credentials.\n\n\n`````md tabs\n\n## OAuth with Databricks\n\n#### Interactive Login with your Databricks Account\n\nIf your workspace administrator has already added Reflex as a Connected App in your Databricks workspace, you should see a \"Login with Databricks\" button after entering your DATABRICKS_HOST.\n\n\n## Service Principal\n\n#### M2M Service Principal (DATABRICKS_CLIENT_ID and DATABRICKS_CLIENT_SECRET)\n\n- Open the dropdown in the top right corner and select **Manage Account**.\n\n![Opening Manage Account in Databricks](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_1.webp)\n\n- Select `Users and Groups`\n\n![Selecting Users and Groups in Databricks account](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_2.webp)\n\n- Select the `Service Principals` tab and click `Add Service Principal`.\n\n![Adding a Databricks service principal](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_3.webp)\n\n- Fill in the details and click `Add Service Principal`.\n\n![Entering Databricks service principal details](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_4.webp)\n\n- Click the `Credentials and Secrets` tab and click `Generate Secret`.\n\n![Generating a Databricks service principal secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_5.webp)\n\n- Set a lifetime for the secrets and click `Generate`.\n\n![Setting Databricks secret lifetime](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_6.webp)\n\n- Copy the generated **DATABRICKS_CLIENT_ID** and **DATABRICKS_CLIENT_SECRET**.\n\n![Copying Databricks client ID and secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_7.webp)\n\n`````\n\n\n\n## Step 2: Configure the Integration in Your App\n\n1. In your app, go to **Integrations** and **Add Databricks**.\n2. Paste your **DATABRICKS_HOST**\n3. Select your authentication method:\n   - OAuth, if configured.\n   - Service Principal, provide the client ID and secret gathered previously.\n2. Paste or select your\n   1. **DATABRICKS_WAREHOUSE_ID**\n   2. **DATABRICKS_CATALOG**\n   3. **DATABRICKS_SCHEMA**  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, the AI Builder can execute queries directly against your Databricks environment.\n\n\n## Step 3: Notes\n\n* **Secure your token:** Never expose tokens in public code.  \n* **Permissions:** Ensure your token or service account has the required workspace and table permissions.\n* **Combine with AI:** Use query outputs to power models, summaries, or alerts in real time.\n\n\n## How to Enable Login as an Admin\n\n- Login to Databricks\n- Go to manage account\n\n![Opening Manage Account as Databricks admin](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_admin_auth_1.webp)\n\n- Go to **Settings** → **Apps Connections** → **Add new connection**\n\n![Adding a new app connection in Databricks settings](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_admin_auth_2.webp)\n\n- Give it a name, enter the redirect URL that Reflex Build provides, Click `All APIs` and uncheck `Generate a client secret` and then add.\n   - URL: `https://build.reflex.dev/_reflex_oidc_databricks/authorization-code/callback`\n\n![Configuring the Reflex redirect URL in Databricks](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_admin_auth_3.webp)\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/descope.md (Tokens: ~469 | Category: anthropic-skill) -->\n---\ntags: Authentication\ndescription: Add Descope’s identity and authentication platform to your apps to manage user sign-in, onboarding, MFA, SSO, and flows with ease.\n---\n# Descope Integration\n\nThe **Descope Integration** enables your app to leverage Descope’s full Customer Identity & Access Management (CIAM) features—visual authentication flows, identity management, SSO, MFA, tenant isolation, and more. Once set up, you can orchestrate secure user journeys across your application with minimal coding.\n\n\n```md alert warning\n# You must open your app in a new tab from the builder to test the Descope integration.\n```\n\n## What You Can Do\n\nWith Descope Integration, your app can:\n- Handle user sign-up, login, and passwordless flows seamlessly  \n- Enable multifactor authentication (MFA), passkeys, and social login  \n- Support single sign-on (SSO) via OIDC/SAML  \n- Manage users, roles, tenants, and permissions via management APIs  \n- Orchestrate onboarding, branding, and multi-tenant flows via drag-and-drop workflows  \n- Sync user data with tools like HubSpot or Segment via built-in connectors\n\n\n## Step 1: Obtain Descope Credentials\n\n![Descope Credentials](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/descope.webp)\n\n1. Log in to the [**Descope Console** (or sign up)](https://www.descope.com/sign-up).\n2. Create your first Project. \n3. Go to the Project page under Settings.\n4. Copy the `Project ID`.\n\n\n## Step 2: Configure the Integration in Your App\n\n1. In your app’s settings or integration dashboard, select **Add Descope**.  \n2. Enter your **PROJECT_ID**.  \n3. (Optional) Pick a **DESCOPE_FLOW_ID** (e.g. “sign-up-or-login”) and **SESSION_SECRET_KEY** or press the Clipboard Copy to use default values.  \n4. Click **Connect** to validate credentials and enable Descope features.\n\n![Descope Integration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/descope_2.webp)\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/gemini.md (Tokens: ~285 | Category: anthropic-skill) -->\n---\ntags: AI\ndescription: Connect your apps to Google’s Gemini models for advanced AI capabilities.\n---\n# Gemini Integration\n\nThe **Gemini Integration** allows your app to use [Google’s Gemini models](https://aistudio.google.com/) for text generation, reasoning, multimodal analysis, and other advanced AI capabilities. Once connected, you can call Gemini directly from your workflows, UI actions, or automated triggers.\n\n## Step 1: Obtain a Gemini API Key\n\n1. Go to [Google AI Studio](https://aistudio.google.com/).\n2. Navigate to **Get API Key** or create a new key for your project.\n3. Copy the generated key.\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Gemini** in your app settings.  \n2. Paste your **Gemini API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Gemini for AI-powered features across workflows and components.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Gemini API key in public code repositories.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys help manage access and security.  \n* **Secure API access:** The key allows your app to interact with Gemini endpoints securely and efficiently.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/github.md (Tokens: ~447 | Category: anthropic-skill) -->\n---\ntags: Developer Tools\ndescription: Connect your app to GitHub to automate workflows, manage repositories, and integrate developer operations.\n---\n# GitHub Integration\n\nThe **GitHub Integration** lets your app connect directly to [GitHub](https://github.com) to automate actions, fetch data, and build powerful developer workflows. Once connected, your app can interact with repositories, issues, pull requests, and more.\n\n## What You Can Do\n\nWith GitHub, your app can:\n- Fetch and display repository data (commits, branches, issues, etc.).  \n- Create or update issues, pull requests, and discussions.  \n- Trigger workflows or CI/CD pipelines.  \n- Sync GitHub activity into your app’s dashboards or automations.  \n- Build custom developer tools using GitHub’s API.\n\n## Step 1: Generate a Personal Access Token\n\n1. Go to your [GitHub Settings](https://github.com/settings/tokens).  \n2. Navigate to **Developer settings → Personal access tokens**.  \n3. Click **Generate new token** (classic or fine-grained).  \n4. Select the required scopes (e.g., `repo`, `workflow`, `read:user`).  \n5. Copy the token.  \n   **Example token:**  \n```\nghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n```\n(Note: Replace the above value with your actual GitHub token)\n\n> 💡 Fine-grained tokens are recommended for better security.\n\n## Step 2: Configure the Integration in Your App\n\n1. In your app, go to **Integrations → Add GitHub**.  \n2. Paste your **GitHub Personal Access Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can start interacting with GitHub through workflows and actions.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Never expose your GitHub token in public code.  \n* **Use fine-grained permissions:** Limit access to only what’s needed.  \n* **API rate limits:** GitHub imposes API limits, so plan automations accordingly.  \n* **Combine with AI:** For example, auto-generate release notes from commits or summarize PRs with LLMs.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/google_auth.md (Tokens: ~475 | Category: anthropic-skill) -->\n---\ntags: Authentication\ndescription: Enable secure authentication using Google sign-in and OAuth 2.0 workflows.\n---\n\n# Google Auth Integration\n\nThe **Google Auth Integration** allows your app to authenticate users using their Google accounts. This provides a secure, familiar login experience and simplifies user management.\n\n\n## Step 1: Create a Google OAuth Client\n\n1 - Go to the [Google Cloud Console](https://console.cloud.google.com/)\n\n2 - Navigate to **APIs & Services → Credentials**\n\n3 - Click **Create Credentials**\n\n![Creating credentials in Google Cloud Console](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_1.webp)\n\n4 - Choose **OAuth client ID**.\n\n![Choosing OAuth client ID credential type](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_2.webp)\n\n5 - Choose **Web Application** as the application type, name the application and enter your sandbox URL, which you get from the Google Auth integration panel, as the **Authorized JavaScript Origin** and **Authorized Redirect URIs**.\n\n![Configuring Google OAuth web application origins](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_3.webp)\n\n6 - Copy the generated **Client ID** (`GOOGLE_CLIENT_ID`) and **Client Secret** (`GOOGLE_CLIENT_SECRET`).\n\n![Copying Google client ID and secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_4.webp)\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Google Auth** in your app settings.\n2. Enter your **Google Client ID** and **Google Client Secret**.\n3. Save the integration. Your app is now configured to use Google Auth for login.\n\n## Step 3: Notes\n\n- The integration supports multiple environments (development, staging, production). Use environment-specific secrets for the client ID and secret.\n- Google Auth handles token refresh automatically when users log in via OAuth.\n- Users will see a standard Google login screen, ensuring familiarity and trust.\n- Ensure your app domain matches the authorized JavaScript origin and redirect URIs; otherwise, authentication will fail.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/groq.md (Tokens: ~343 | Category: anthropic-skill) -->\n---\ntags: AI\ndescription: Connect your apps to Groq’s ultra-fast inference API for lightning-speed AI responses.\n---\n# Groq Integration\n\nThe **Groq Integration** allows your app to use [Groq’s API](https://groq.com/) for ultra-fast AI inference. Once connected, your app can leverage Groq’s hosted models (including open models like Llama 4 and Qwen) to power real-time workflows, chat experiences, and other AI-driven features.\n\n## Step 1: Obtain a Groq API Key\n\n1. Go to the [Groq Console](https://console.groq.com/).  \n2. Navigate to **API Keys** in your account settings.  \n3. Click **Create API Key** and give it a descriptive name (e.g., “AI Builder”).  \n4. Copy the generated key.\n   * **Example:** `gsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Groq** in your app settings.  \n2. Paste your **Groq API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Groq to deliver ultra-low latency AI responses across workflows and components.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Groq API key in public code repositories.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys help manage access and security.  \n* **Secure API access:** The key allows your app to interact with Groq endpoints securely and efficiently.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/hubspot.md (Tokens: ~352 | Category: anthropic-skill) -->\n---\ntags: Data Infrastructure\ndescription: Connect your apps to HubSpot to manage contacts, companies, deals, and marketing workflows.\n---\n# HubSpot Integration\n\nThe **HubSpot Integration** allows your app to use [HubSpot](https://www.hubspot.com/) as a CRM and marketing automation platform. Once connected, your app can sync leads, manage contacts, update pipelines, and trigger workflows directly from user actions or automated events.\n\n## Step 1: Obtain a HubSpot Access Token\n\n1. Go to your [HubSpot Developer Account](https://developers.hubspot.com/).  \n2. Navigate to **App → Private Apps** in your account settings.  \n3. Click **Create Private App**, configure scopes (e.g., `crm.objects.contacts.read/write`, `crm.schemas.companies.read`), and save.  \n4. Copy the **Access Token** from the Auth tab.\n   * **Example:** `pat-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add HubSpot** in your app settings.  \n2. Paste your **HubSpot Access Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can sync and manage HubSpot data directly from workflows and UI actions.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Do not hardcode your HubSpot token in public code repositories.  \n* **Use environment-specific tokens:** Separate dev, staging, and production tokens to manage access.  \n* **Secure API access:** The token allows your app to interact with HubSpot endpoints securely and efficiently.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/hugging_face.md (Tokens: ~471 | Category: anthropic-skill) -->\n---\ntags: AI\ndescription: Connect your apps to Hugging Face to access thousands of open models for text, vision, and multimodal tasks.\n---\n# Hugging Face Integration\n\nThe **Hugging Face Integration** allows your app to use [Hugging Face](https://huggingface.co/) models for a wide range of AI tasks — including text generation, embeddings, translation, classification, image processing, and more. You can integrate both hosted models (via API) or local open-source models through the Transformers library.\n\n## What You Can Do\n\nWith Hugging Face, your app can:\n- Access thousands of pre-trained **text, vision, and multimodal models**.  \n- Run **text generation**, summarization, translation, and classification tasks.  \n- Use **embeddings** for search, retrieval, and similarity.  \n- Deploy models locally with `transformers` or connect to hosted inference endpoints.  \n- Fine-tune or customize open models for your specific use cases.  \n- Integrate community and enterprise models seamlessly into workflows.\n\n## Step 1: Obtain a Hugging Face Access Token (Optional)\n\n1. Go to [Hugging Face](https://huggingface.co/).  \n2. Log in or create a free account.  \n3. Navigate to **Settings → Access Tokens**.  \n4. Click **Create New token**, set its scope, and copy it.\n   * **Example:** `hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Hugging Face** in your app settings.  \n2. Paste your **Hugging Face Access Token** if required.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Hugging Face models directly in workflows, UI actions, or automations.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Never expose your Hugging Face token in client-side code.  \n* **Use environment-specific tokens:** Separate dev, staging, and production access.  \n* **Open-source flexibility:** Models can be run fully locally or through Hugging Face’s hosted endpoints.  \n* **Broad ecosystem:** Hugging Face supports thousands of community and commercial models for rapid prototyping and production use.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/langchain.md (Tokens: ~322 | Category: anthropic-skill) -->\n---\ntags: AI\ndescription: Connect your apps to Langchain for advanced AI capabilities.\n---\n# Langchain Integration\nThe **LangChain Integration** allows your app to leverage the power of [LangChain](https://langchain.com/), a popular open-source framework for building applications with large language models (LLMs). Once connected, your app can orchestrate complex AI workflows, chain together multiple model calls, and integrate with various data sources and tools seamlessly.\n\n\nYou can:\n\n* **Chain model calls together** to create multi-step reasoning flows.\n* **Connect multiple providers** (e.g., OpenAI, Anthropic, Gemini, Groq) through a single interface.\n* **Build intelligent agents** that can use tools, call APIs, or access external data sources dynamically.\n* **Work with structured data** by combining LLMs with databases, vector stores, and retrieval systems.\n* **Create RAG (Retrieval-Augmented Generation)** pipelines to ground model outputs in your own data.\n* **Integrate tools and memory** so models can reason over past interactions and context.\n* **Deploy reusable components** like prompt templates, chains, and agents for production-grade applications.\n\nLangChain essentially acts as a **“glue layer”** between language models, data, and logic — enabling teams to build more **powerful and reliable AI apps** without reinventing core orchestration features.\n\n\n## Configure the Integration in Your App\n\n1. Click the **Settings** gear icon and navigate to the **Integrations** tab.\n2. Find and enable the **LangChain** integration.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/linear.md (Tokens: ~418 | Category: anthropic-skill) -->\n---\ntags: DevTools\ndescription: Connect your apps to Linear to manage issues, projects, and sprints directly from workflows.\n---\n# Linear Integration\n\nThe **Linear Integration** allows your app to connect to [Linear](https://linear.app/) to create, update, and track issues and projects seamlessly. Once connected, your app can trigger Linear actions from user interactions or automated workflows.\n\n## What You Can Do\n\nWith Linear, your app can:\n- **Create and assign issues** automatically from user actions or AI workflows.  \n- **Update status and priority** of tickets and projects.  \n- **Sync with sprints and cycles** to keep work organized.  \n- **Fetch project and issue data** for dashboards, summaries, or automation.  \n- **Integrate with other tools** like Slack or GitHub through workflows.  \n- Power intelligent workflows (e.g., auto-triage or auto-summarize bug reports).\n\n## Step 1: Obtain a Linear API Key\n\n1. Go to your [Linear account](https://linear.app/).  \n2. Navigate to **Workspace Settings → API**.  \n3. Click **Create API Key**, give it a name, and copy the key.\n\n   * **Example:** `lin_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Linear** in your app settings.\n2. Paste your **Linear API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can interact with Linear to automate issue tracking and project management.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Never expose your Linear API key in client-side code.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys.  \n* **Streamlined workflows:** Automate ticket creation, status updates, and reporting directly from your app.  \n* **Real-time visibility:** Fetch and sync project data to power internal tools or dashboards.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/notion.md (Tokens: ~464 | Category: anthropic-skill) -->\n---\ntags: Data Infrastructure\ndescription: Connect your apps to Notion to create, update, and query pages, databases, and documents.\n---\n# Notion Integration\n\nThe **Notion Integration** allows your app to connect to [Notion](https://www.notion.so/) to manage content, automate workflows, and build dynamic interfaces on top of Notion workspaces. Once connected, your app can read and write pages, sync databases, and trigger actions based on user activity.\n\n## What You Can Do\n\nWith Notion, your app can:\n- **Create and update pages** in workspaces automatically.  \n- **Read and query databases** to power dashboards, workflows, or automations.  \n- **Sync structured content** like tasks, notes, or documentation with other tools.  \n- Trigger **actions from AI workflows** (e.g., creating meeting notes, logging issues).  \n- Integrate with other services (e.g., Slack, Linear, HubSpot) for seamless collaboration.\n\n## Step 1: Obtain a Notion API Token\n\n1. Go to the [Notion Developers](https://www.notion.so/my-integrations) page.  \n2. Click **+ New Integration**, give it a name, and copy the generated **Internal Integration Token**.  \n3. Share the integration with the relevant pages or databases in your workspace to grant access.\n\n   * **Example:** `ntn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Notion** in your app settings.  \n2. Paste your **Notion API Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can read and write to Notion directly from workflows and UI actions.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Never expose your Notion token in client-side code.  \n* **Use environment-specific tokens:** Separate dev, staging, and production access.  \n* **Granular permissions:** Only share the integration with the pages or databases it needs to access.  \n* **Powerful building block:** Use Notion as a single source of truth for content, tasks, or structured data.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/okta_auth.md (Tokens: ~834 | Category: anthropic-skill) -->\n---\ntags: Authentication\ndescription: Use Okta for secure identity and access management via Single Sign-On provisioning.\n---\n\n# Okta Auth Manager Integration\n\nThe **Okta Auth Manager Integration** allows your app to authenticate users through [Okta](https://okta.com). This integration provides secure OAuth 2.0 / OIDC authentication and supports multi-tenant environments with customizable access policies.\n\n\n## What You Can Do\n\nWith Okta, your app can:\n- Authenticate users securely through Okta’s identity platform.  \n- Enable **SSO** for enterprise users.  \n- Manage user roles, groups, and access permissions.  \n- Protect sensitive data and actions with **OAuth 2.0** and **OpenID Connect (OIDC)**.  \n- Integrate with other identity workflows like MFA or adaptive policies.\n\n\n## Step 1: Set Up Okta OIDC App\n\nBefore connecting, you need to create an OIDC application in the Okta Admin Console:\n\n1 - Go to [Okta Admin Console](https://login.okta.com) → **Applications** → **Applications**\n\n\n2 - Click **Create App Integration**\n\n![Creating an Okta app integration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_1.png)\n\n3 - Select **OIDC – OpenID Connect** and choose **Web Application**\n\n![Selecting OIDC web application in Okta](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_2.png)\n\n4 - Configure your app settings:\n   - **Allow wildcard * in sign-in redirect URIs**\n   - **Sign-in redirect URIs** found in the Okta Auth Manager integration settings in AI Builder:\n     `https://{your-sandbox}/authorization-code/callback`\n   - **Sign-out redirect URIs**:\n     `https://{your-sandbox}`\n   - Assign to the correct **Group** or **Everyone** depending on your access control\n\n![Configuring Okta sign-in redirect URIs](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_3.png)\n\n5 - Save the app integration.\n\n6 - Copy your **Client ID** (`OKTA_CLIENT_ID`) and **Client Secret** (`OKTA_CLIENT_SECRET`) from the app settings.\n\n![Copying Okta client ID and secret](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_4.png)\n\n\n## Step 2: Finding Your Okta Issuer URI\n\n1. In the Okta Admin Console, go to **Security** → **API** → **Authorization Servers**\n2. Click on the **default** server and copy the **Issuer URI**.\n3. Remove the trailing `/oauth2/default` from the URI to get your **Okta Issuer URI** (`OKTA_ISSUER_URI`).\n\nExample:\n\nIf your Issuer URI is `https://{yourOktaDomain}.okta.com/oauth2/default`\n\nUse `https://{yourOktaDomain}.okta.com`\n\n![Finding the Okta issuer URI](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_5.png)\n\n\n> **Note:** Always use separate Okta apps for dev, staging, and production environments to avoid mixing credentials.\n\n\n## Step 3: Configure the Integration\n\n1. Go to the **Integrations** section in your app settings by clicking **`@`** and then selecting the **Integrations** tab.\n2. Click **Add** next to **Okta Auth Manager**.\n3. Fill in the credential fields:\n   - Enter your Okta Client ID\n   - Enter your Okta Client Secret\n   - Enter your Okta Issuer URI\n4. Click **Connect** to save the integration.\n\nYour app can now authenticate users through Okta using the secure OAuth 2.0 / OIDC flow.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/openai.md (Tokens: ~258 | Category: anthropic-skill) -->\n---\ntags: AI\ndescription: Connect to OpenAI's powerful language models for text generation, analysis, and more.\n---\n# OpenAI Integration\n\nThe **OpenAI Integration** allows your app to use OpenAI APIs for features such as text generation, embeddings, and other AI-powered functionality.\n\n## Step 1: Obtain an OpenAI API Key\n\n1. Go to the [OpenAI Platform](https://platform.openai.com/).\n2. Navigate to **API Keys** in your account settings.\n3. Click **Create new secret key**.\n4. Copy the generated key.\n   - Example: `sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add OpenAI Integration** in your app settings.\n2. Enter your **OpenAI API Key** in the input field.\n3. Save the integration. Your app is now ready to make OpenAI API requests.\n\n---\n\n## Step 3: Notes\n\n- Keep your OpenAI key secure; do **not** hardcode it in public code repositories.\n- Use environment-specific secrets if you have separate development, staging, and production environments.\n- The key allows your app to interact with OpenAI endpoints securely and efficiently.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/overview.md (Tokens: ~27 | Category: anthropic-skill) -->\n```python exec\nfrom pcweb.pages.integrations.integration import integration_page\n```\n\n```python eval\nintegration_page()\n```\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/perplexity.md (Tokens: ~470 | Category: anthropic-skill) -->\n---\ntags: AI\ndescription: Connect your apps to Perplexity to power real-time, retrieval-augmented AI experiences.\n---\n# Perplexity Integration\n\nThe **Perplexity Integration** allows your app to use [Perplexity](https://www.perplexity.ai/) to deliver fast, accurate, retrieval-augmented answers from the web and trusted sources. Once connected, you can use Perplexity to enhance search, summarization, and real-time knowledge in your workflows.\n\n## What You Can Do\n\nWith Perplexity, your app can:\n- **Retrieve real-time information** from the web to ground model outputs.  \n- **Generate concise summaries** and answers with citations.  \n- Power **search experiences**, research assistants, and contextual AI features.  \n- **Combine Perplexity with other models** for hybrid workflows (e.g., retrieval + reasoning).  \n- Enable **trusted, source-backed outputs** for more accurate responses.\n\n## Step 1: Obtain a Perplexity API Key\n\n1. Go to the [Perplexity](https://www.perplexity.ai/).  \n2. Log in or create an account.  \n3. Navigate to **Account → API → [API Keys](https://www.perplexity.ai/account/api/keys)**.  \n4. Click **Generate Key** and copy the generated key.\n\n   * **Example:** `pplx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Perplexity** in your app settings.  \n2. Paste your **Perplexity API Key** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can use Perplexity for retrieval-augmented AI features across workflows and components.\n\n## Step 3: Notes\n\n* **Keep your key secure:** Do not hardcode your Perplexity API key in public code repositories.  \n* **Use environment-specific keys:** Separate dev, staging, and production keys for better control.  \n* **Secure API access:** The key allows your app to interact with Perplexity endpoints securely and efficiently.  \n* **Real-time power:** Perplexity is ideal for use cases where freshness and factual grounding matter.\n\n<!-- File: packages/integrations-docs/src/integrations_docs/docs/replicate.md (Tokens: ~429 | Category: anthropic-skill) -->\n---\ntags: AI\ndescription: Connect your apps to Replicate to run and deploy open-source machine learning models with ease.\n---\n# Replicate Integration\n\nThe **Replicate Integration** allows your app to use [Replicate](https://replicate.com/) to run open-source AI models in the cloud without managing infrastructure. Once connected, you can use Replicate to generate text, images, audio, and more — directly from workflows and UI actions.\n\n## What You Can Do\n\nWith Replicate, your app can:\n- Run open-source **AI models** without GPU or hosting setup.  \n- Access models for **text generation**, **image generation**, **audio**, and **multimodal tasks**.  \n- Automate workflows like content generation, data processing, or AI-powered features.  \n- Use prebuilt models or deploy your own custom models.  \n- Scale effortlessly with serverless infrastructure.\n\n## Step 1: Obtain a Replicate API Token\n\n1. Go to the [Replicate Dashboard](https://replicate.com/account).  \n2. Log in or create an account.\n3. Navigate to the **API Tokens** section.  \n4. Copy your **API Token** from the account page.\n\n   * **Example:** `r8_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\n\n## Step 2: Configure the Integration in Your App\n\n1. Go to **Integrations → Add Replicate** in your app settings.  \n2. Paste your **Replicate API Token** in the input field.  \n3. Click **Connect** to validate and save your integration.\n\nOnce connected, your app can call Replicate models directly in workflows, UI actions, or automations.\n\n## Step 3: Notes\n\n* **Keep your token secure:** Do not hardcode your Replicate token in public code repositories.  \n* **Use environment-specific tokens:** Separate dev, staging, and production environments for security.  \n* **Secure API access:** The token allows your app to interact with Replicate endpoints safely and efficiently.  \n* **Model flexibility:** You can use community models or deploy your own for full control.\n\n<!-- ... +33 more modular skills available via /api/skills/reflex-dev/reflex?path={path} -->\n</yakaai_skills>"}