{"owner":"PrefectHQ","repo":"prefect","hasSkills":true,"totalSkillsCount":13,"totalTokensCount":19398,"categories":["anthropic-skill","root-instruction","command-prompt","claude-rule"],"hasMcp":false,"mcpConfig":null,"found":[".claude/skills/agents-md-sync/SKILL.md","client/AGENTS.md",".claude/skills/backlog-management/SKILL.md","AGENTS.md",".claude/skills/document-changes/SKILL.md",".claude/skills/write-docs/SKILL.md","integration-tests/AGENTS.md","docs/AGENTS.md",".claude/commands/repro.md",".claude/skills/write-docs/template-concept.mdx","ui-v2/AGENTS.md","tests/AGENTS.md",".claude/skills/write-docs/template-howto.mdx"],"skills":{".claude/skills/agents-md-sync/SKILL.md":"---\nname: agents-md-sync\ndescription: Analyze code changes on the current branch and recommend updates to AGENTS.md files that have become stale. Use this skill before creating a PR, when the user asks to check AGENTS.md freshness, or when preparing an AGENTS.md update after a PR merges to main. Trigger whenever the user mentions syncing, updating, or checking AGENTS.md files, or when they're about to create a PR that touches code structure (new modules, renamed directories, changed commands, modified architecture).\n---\n\n# AGENTS.md Sync\n\nDetect when code changes make durable AGENTS.md guidance stale and produce a report with specific recommendations. Treat AGENTS.md files as operating manuals for future agents, not changelogs for recent diffs.\n\n## When to use\n\n- Before creating a PR — check if the branch's changes warrant AGENTS.md updates\n- After a PR merges to main — audit whether merged changes left AGENTS.md files outdated\n- On explicit request — \"are the AGENTS.md files up to date?\"\n\n## Workflow\n\n### 1. Determine the diff\n\nFigure out what changed relative to the base branch. The approach depends on context:\n\n- **On a feature branch (pre-PR):** diff against main\n  ```bash\n  git diff main...HEAD --name-status\n  git diff main...HEAD\n  ```\n- **After a merge to main:** the user should specify which PR or commit range to audit. Use the merge commit or PR number to get the diff:\n  ```bash\n  gh pr diff <number>\n  ```\n- **Explicit check:** if the user just says \"check AGENTS.md\", diff against main\n\n### 2. Map changes to AGENTS.md territories\n\nEach AGENTS.md file \"owns\" the directory it lives in and all subdirectories (unless a child directory has its own AGENTS.md). Build a list of which AGENTS.md files are relevant by walking up from each changed file to find the nearest AGENTS.md.\n\nExample: a change to `src/prefect/server/api/flows.py` is owned by `src/prefect/server/AGENTS.md` (if it exists), otherwise `src/prefect/AGENTS.md`.\n\nOnly analyze AGENTS.md files that have at least one changed file in their territory. Also include parent AGENTS.md files if structural changes (new directories, moved files) affect the directory tree they document.\n\n### 3. Check for missing AGENTS.md files\n\nBefore analyzing existing AGENTS.md files, check whether any changed directories *should* have their own AGENTS.md but don't. New AGENTS.md files should be rare. Recommend one only when the directory has both:\n\n- A real ownership boundary that a future agent needs to recognize before editing\n- Hidden conventions, non-obvious contracts, or recurring pitfalls that cannot be learned quickly from reading the code\n\nLook at the directories containing changed files. For each one that lacks an AGENTS.md, check:\n1. **Ownership boundary**: Does this directory represent a responsibility shift with different contracts than its parent?\n2. **Hidden knowledge**: Are there non-obvious patterns, invariants, conventions, or failure modes that a developer would not learn quickly from code?\n3. **Durability**: Will this guidance still matter after the triggering PR is old news?\n4. **Hierarchy fit**: Would this belong better in an existing parent AGENTS.md instead?\n\nDirectory size and sibling AGENTS.md files can be weak signals, but they are never sufficient on their own. Do not recommend a new AGENTS.md just because a directory has 5+ files, gained a new module, or has sibling directories with AGENTS.md files.\n\nWhen the case is not high-confidence, do not create the file. Capture the possible update as a recommendation instead, with the missing evidence or question that would make it actionable.\n\nWhen recommending a new AGENTS.md, use the Explore agent to read the directory's code and draft the file using this template:\n\n```markdown\n# <Module Name>\n\n<One-sentence purpose statement.>\n\n## Purpose & Scope\n\nWhat this module does. Explicit responsibility boundaries.\nWhat it does NOT do (prevents scope creep).\n\n## Entry Points & Contracts\n\nKey APIs, functions, classes that external consumers use.\nInput/output contracts. Invariants that must hold.\n\n## Usage Patterns\n\nCanonical examples of correct usage.\n\"If you need to do X, here's how.\"\n\n## Anti-Patterns\n\nWhat NOT to do. Common mistakes. Each should be a real mistake, not hypothetical.\n\n## Pitfalls\n\nNon-obvious gotchas. Implicit assumptions.\n\"You'd think X, but actually Y because Z.\"\n```\n\nThe initial content must be concise and durable. Do not include `[ASK]` placeholders, file lists, changelog context, or speculative guidance. If the hidden knowledge cannot be stated confidently, write a recommendation instead of creating the file.\n\n### 4. Analyze each relevant AGENTS.md\n\nAGENTS.md files form a hierarchy — when an agent loads any file, all ancestor files load too, creating a T-shaped view (broad context at the top, specific detail where the agent works). This has two implications for the sync check:\n\n**Least common ancestor rule**: Shared knowledge should live at the shallowest AGENTS.md that covers all paths needing it. If the same fact appears in multiple sibling AGENTS.md files, flag it — it should move to their parent. Conversely, if a parent AGENTS.md contains detail that only applies to one child directory, suggest moving it down.\n\n**Upward propagation**: When a child AGENTS.md changes (or a new one is created), check whether the parent needs updating — either to add a cross-reference to the new child, or to re-summarize what the child directory does. Parent nodes should summarize their children's responsibilities, not duplicate their details.\n\nFor each AGENTS.md in scope, read it fully, then compare its claims against the diff **and** the current source code. Look for these categories of issues:\n\n**Accuracy** — claims in AGENTS.md that don't match the actual code, regardless of whether the diff caused the discrepancy:\n- Described behaviors that don't match what the code actually does (e.g., \"renews at 75% of duration\" when it actually renews immediately then sleeps 75%)\n- Function signatures or parameters listed that are wrong or incomplete\n- Responsibilities attributed to the wrong layer or module\n- Error handling or failure modes described incorrectly\n\nFor claims that are verifiable (specific behaviors, function signatures, which module does what), read the source file and confirm. Don't trust that existing AGENTS.md content was ever correct — it may have been wrong from the start.\n\n**Signal density** — content that duplicates what's discoverable from code rather than surfacing hidden knowledge:\n- Full function signatures that just repeat the code (the *contracts* and *gotchas* around those functions are the high-signal parts)\n- Trivial usage examples that match what's in docstrings or is obvious from the API\n- File-by-file directory listings that `ls` would show — the *layering concept* or *architectural invariant* matters, not the enumeration\n- Content that a developer would learn in 30 seconds of reading the source\n\nAGENTS.md should capture what's *not* visible in the code: invariants, hidden contracts, non-obvious failure modes, things that look one way but behave another.\n\nA behavior discovered in one changed function is not AGENTS-worthy by default.\nPromote it only if it exposes a subsystem-level editing rule, a cross-file\ncontract, or a recurring failure mode future agents need before choosing\nwhich implementation to read. Otherwise prefer a code comment, docstring,\ntest name, or no documentation change.\n\nIf the same guidance is already present in nearby code comments, docstrings, or tests, AGENTS.md should usually not repeat it.\n\n**Missing invariants** — implicit contracts the code relies on that aren't documented:\n- Parallel implementations that must stay in sync (e.g., sync and async versions of the same module)\n- Ordering requirements or sequencing constraints\n- Singleton behaviors or shared mutable state\n- Cleanup responsibilities and what happens when they're skipped\n- \"This looks stateless but actually depends on X\"\n\n**Structural drift** — the AGENTS.md describes an ownership boundary, durable package layout, or module responsibility that no longer matches reality:\n- Directories or packages added/removed/renamed in a way that changes responsibility boundaries\n- New architectural layers or cross-file contracts not mentioned\n- Removed components still listed as active responsibilities\n\n**Command drift** — documented commands that may no longer work or are incomplete:\n- Build/test/run commands referencing changed entry points\n- New tooling or scripts not mentioned\n\n**Convention drift** — code patterns or conventions described in AGENTS.md that the diff contradicts:\n- New patterns established by the changes that aren't documented\n- Existing conventions the changes deprecate or replace\n\n**Description drift** — prose descriptions that no longer accurately characterize the code:\n- Component descriptions that miss new responsibilities\n- Architecture notes that don't reflect refactoring\n\n**Hierarchy drift** — content living at the wrong level in the AGENTS.md tree:\n- Knowledge duplicated across sibling AGENTS.md files that should be in their parent (least common ancestor)\n- Parent-level detail that only applies to one child directory\n- Parent summaries of child directories that no longer match after changes\n\nFor each finding, check whether it's actually stale — read the current state of the filesystem (not just the diff) to confirm. A diff showing a new file, helper, flag, or one-off fix doesn't mean AGENTS.md is wrong if AGENTS.md intentionally omits that level of detail.\n\nOnly recommend or apply updates for high-confidence, lasting guidance:\n- Architectural boundaries\n- Non-obvious invariants\n- Cross-file contracts\n- Recurring failure modes\n- Commands or conventions that future agents are likely to need\n\nDo not document:\n- One-off implementation details or temporary bug context\n- Facts obvious from reading names, imports, or nearby code\n- File lists or every new module\n- Changelog-style summaries of the triggering diff\n- Advice that only matters for the current PR\n\n### 5. Produce the report\n\nOutput a concise report grouped by AGENTS.md file. For each file, list findings with:\n- **What's stale** — the specific line or section\n- **Why** — which change caused it\n- **Suggested fix** — the concrete text to add, remove, or change\n\nFormat:\n\n```markdown\n## AGENTS.md Sync Report\n\n### New AGENTS.md recommended: `src/prefect/utilities/`\n\nThis directory now owns a distinct retry protocol used by multiple callers, and contributors must preserve its ordering invariant. Suggested outline:\n- Purpose and ownership boundary\n- Ordering invariant that callers rely on\n- Failure mode to test when changing it\n\n### `src/prefect/server/AGENTS.md`\n\n1. **[Accuracy]** Lease renewal described as \"renews at 75% of duration\" but code renews immediately then sleeps 75%\n   - Caused by: incorrect from initial creation\n   - Suggested fix: \"renews immediately on entry, then sleeps for 75% of `lease_duration` between renewals\"\n\n2. **[Signal density]** Full function signatures duplicate the code — remove parameter lists, keep contracts\n   - Suggested fix: Replace `concurrency(names, occupy=1, ...)` with `concurrency()` and describe the non-obvious behaviors instead\n\n3. **[Missing invariant]** Sync and async implementations must stay in lockstep but this isn't documented\n   - Suggested fix: Add \"Any behavior change to `_asyncio.py` must be mirrored in `_sync.py`\"\n\n4. **[Structural]** New directory `src/prefect/server/events/` not listed in directory structure\n   - Caused by: `src/prefect/server/events/` added in this branch\n   - Suggested fix: Add `events/` to the directory listing with description\n\n### `./AGENTS.md` (root)\nNo changes needed.\n```\n\nIf nothing is stale, say so clearly — don't manufacture findings.\n\n### 6. Offer next steps\n\nAfter presenting the report, offer:\n- **Apply fixes** — make the suggested edits directly\n- **Create a follow-up PR** — if this is a post-merge audit, offer to create a branch and PR with just the AGENTS.md updates\n- **Skip** — if the changes are minor or the user disagrees with the suggestions\n\n## Reactive mode\n\nOutside of diff-driven analysis, if during normal development you discover missing context that should be in an AGENTS.md, propose an addition. Signs of missing context:\n\n- You spent nontrivial time reconstructing a durable invariant that could be a one-liner in AGENTS.md\n- You hit a non-obvious error because of an undocumented constraint\n- You discovered a cross-system dependency that isn't mentioned anywhere\n- A code review caught something that AGENTS.md should have prevented\n\nPropose additions like this:\n```\nI discovered that [finding]. This isn't in [path]/AGENTS.md.\n\nProposed addition to the [section] section:\n> [concrete text to add]\n\nShould I add this?\n```\n\n## Quality checks for new or updated AGENTS.md content\n\n- **Compression**: Can any section be shorter without losing information?\n- **Deduplication**: Does anything repeat what a parent AGENTS.md already says? If so, remove it and rely on the hierarchy.\n- **Specificity**: Replace vague statements with concrete ones. Not \"be careful with auth\" but \"place logic after the `require_*` call\".\n- **Target length**: 20-80 lines for new files. If longer, compress or write recommendations instead.\n\n## Important guidelines\n\n- Be conservative — only flag things that are genuinely wrong or missing. AGENTS.md files are intentionally concise and don't need to document every file.\n- Don't suggest adding content that's obvious from the code itself. AGENTS.md captures non-obvious patterns, gotchas, and high-level structure. Equally, flag *existing* content that merely restates the code — full function signatures, trivial examples, and file enumerations are low-signal and should be trimmed or replaced with the hidden knowledge around them.\n- Don't trust that existing AGENTS.md content was ever correct. Verify factual claims (behaviors, signatures, responsibility attribution) against the source code, not just against the diff. Content can be wrong from day one.\n- Don't suggest stylistic rewrites. Focus on factual accuracy and signal density.\n- When in doubt about whether something is stale, check the filesystem to confirm rather than guessing from the diff alone.\n- Respect the existing level of detail in each AGENTS.md. If a file only lists top-level directories, don't suggest adding individual files.\n- Look for undocumented invariants — parallel implementations that must stay in sync, ordering constraints, singleton behaviors, cleanup responsibilities. These are the highest-value additions because they're invisible in code and cause the most breakage when violated.\n","client/AGENTS.md":"# prefect-client Package Build\n\nBuild configuration for `prefect-client`, a lightweight subset of `prefect` published as a separate PyPI package. This directory does **not** contain source code — it selects files from `src/prefect/` and repackages them.\n\n## Key Contracts\n\n- **Dependency changes in root `pyproject.toml` that affect client-side code must be mirrored in `client/pyproject.toml`.** This is the most common source of build failures.\n- **New imports in `src/prefect/` can break this build** if they pull in server-only dependencies. The build strips server code, so any import that reaches `server/database`, `server/models`, etc. from client-side code will fail.\n- **The build is tested automatically on every PR** via `.github/workflows/prefect-client.yaml`.\n\n## How It Works\n\n`build_client.sh` copies `src/prefect/` into a temp directory, **deletes** server-only and CLI code, then builds with `client/pyproject.toml`. The resulting package has the same version as `prefect` but fewer dependencies.\n\n### What gets removed\n\n- `cli/` — entire CLI\n- `server/` — database, models, orchestration, schemas, services, utilities (keeps only `server/api/`)\n- `deployments/recipes/` and `deployments/templates/`\n- `testing/`\n\n## Build Triggers\n\n- **PR created** — CI builds and smoke-tests\n- **GitHub release published** — CI builds and publishes to PyPI (same version as `prefect`)\n- **Manual** — `bash client/build_client.sh`\n\nIf the CI build fails, reproduce locally with `bash client/build_client.sh` and run the smoke tests (`client_flow.py`, `client_deploy.py`).\n\n## Related\n\n- `src/prefect/client/` → Actual client SDK source code\n- Root `pyproject.toml` → Must stay in sync with `client/pyproject.toml` for shared dependencies\n",".claude/skills/backlog-management/SKILL.md":"---\nname: backlog-management\ndescription: Manage open-source GitHub issue backlogs (especially PrefectHQ/prefect) in batches. Use for backlog cleanup days, stale review, duplicate pruning, missing-info follow-up, and prioritized queue curation across many open issues.\n---\n\n# Backlog Management\n\nUse this skill for batch backlog work, not for deep triage of a single new issue.\n\n## Scope\n\n- Open-source repositories only.\n- Use public, contributor-friendly language.\n- Do not reference internal plans or private project context.\n\n## Default Mode\n\n- Work in batches of 25-100 issues.\n- Start in read-only mode and propose actions first.\n- Apply edits only after approval unless explicitly asked to execute immediately.\n\n## Workflow\n\n1. Build a candidate batch.\n2. Assign one primary action per issue.\n3. Deep-dive only close candidates.\n4. Draft concise comments where needed.\n5. Apply approved edits.\n6. Report outcomes with counts and issue links.\n\n## Two-Pass Review Depth\n\nUse two passes by default:\n\n- Pass 1 (sweep): classify quickly across the full batch.\n- Pass 2 (dig-in): re-review only `close-not-planned` and `close-duplicate` candidates.\n\nDo not finalize close actions from Pass 1 alone.\n\nFor Pass 2, require explicit evidence:\n\n- architecture/status check against current Prefect behavior\n- concrete links (issue comments, PRs, release notes, docs, code)\n- counterevidence (why issue might still be valid)\n- confidence (`low`, `medium`, `high`)\n\nIf evidence is weak or mixed, downgrade close to:\n\n- `needs:details`\n- `needs:mre`\n- `status:stale`\n- `keep-open`\n\nUI replatform exception:\n\n- Prefect currently has both legacy UI code (`ui/`) and the React replatform (`ui-v2/`).\n- For UI issues that appear tied to legacy UI behavior, do not close based only on age/architecture drift until `ui-v2` is GA.\n- Before proposing close, check whether the reported behavior is represented in `ui/`, `ui-v2/`, or both.\n- Default action before GA is `keep-open` (or `status:stale` only if explicitly desired by maintainers).\n\n## Candidate Queries (PrefectHQ/prefect)\n\nUse focused searches:\n\n```bash\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue no:assignee sort:updated-asc\" --limit 100\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue label:status:stale sort:updated-asc\" --limit 100\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue label:bug -label:needs:mre sort:updated-asc\" --limit 100\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue label:needs:details sort:updated-asc\" --limit 100\n```\n\n## Action Set\n\nChoose exactly one primary action per issue:\n\n- `keep-open`: still actionable, no immediate label change needed\n- `needs:details`: missing context blocks progress\n- `needs:mre`: bug report lacks minimal reproducible example\n- `status:stale`: inactive and low-signal, not exempt\n- `close-duplicate`: close with canonical issue link\n- `close-not-planned`: close with concise reason when clearly out of scope or no longer actionable\n\n## Deep-Dive Output Format\n\nFor every close candidate, produce this mini-record before execution:\n\n- `issue`: number + title\n- `claim_to_verify`: why it appears closable\n- `current_state_check`: does claim still hold today?\n- `evidence_links`: specific references\n- `counterevidence`: any signal to keep open\n- `recommended_action`: final action after deep-dive\n- `confidence`: low/medium/high\n\n## Real Labels (PrefectHQ/prefect)\n\nOnly use labels that exist in this repo. Key labels for backlog work include:\n\n- `needs:details`\n- `needs:mre`\n- `status:stale`\n- `needs:triage`\n- `question`\n- `bug`\n- `enhancement`\n- `good first issue`\n- `blocked`\n- `status:exempt`\n\nVerify labels before applying changes:\n\n```bash\ngh label list --repo PrefectHQ/prefect --limit 30\n```\n\n## Comment Templates\n\nMissing details:\n\n```text\nThanks for opening this. We need a bit more detail before we can move this forward:\n- expected behavior\n- actual behavior\n- exact steps to reproduce\n```\n\nMissing MRE:\n\n```text\nThanks for the report. Please share:\n1) a minimal reproducible code sample,\n2) full traceback/error text,\n3) output of `prefect version`.\n```\n\nDuplicate close:\n\n```text\nClosing as a duplicate of #<issue-number> so discussion stays in one place.\nIf this is materially different, tag me and comment with details; we can reopen.\n```\n\n## Guardrails\n\n- Do not close issues only because they are old.\n- Do not mark as stale when clear maintainer/reporter activity is recent.\n- Do not apply conflicting labels.\n- Do not over-explain; keep comments short and specific.\n- Do not close legacy-UI issues before `ui-v2` GA unless there is a strong non-UI reason (for example, duplicate with active canonical issue).\n","AGENTS.md":"Prefect is a workflow orchestration platform that coordinates and observes data pipelines. It provides a Python SDK for building workflows, a server backend for orchestration, and a web-based UI for managing and monitoring workflows.\n\n# Guiding Principles\n\nYour primary responsibility is to the project and its users. Every change should serve the broader user base — not just the immediate request. Be a quality gate: prefer correct, minimal, well-tested changes over fast ones.\n\n# Before You Start\n\nBefore making code changes, read the public contribution guide in `docs/contribute/dev-contribute.mdx` so your work follows Prefect's contribution expectations, design principles, AI-use policy, testing standards, and maintainer review criteria.\nFor documentation-only changes, also read `docs/contribute/docs-contribute.mdx`.\nFor integration changes, also read `docs/contribute/contribute-integrations.mdx`.\n\n# Directory Structure\n\n```\nprefect/\n├── benches/                         # Benchmarks (CLI, flows, tasks, imports)\n├── client/                          # prefect-client build: subset of src/prefect/ published as a separate PyPI package\n├── compat-tests/                    # Tests for REST API compatibility with Prefect Cloud\n├── Dockerfile                       # Production container image\n├── docs/                            # Mintlify documentation (see docs/AGENTS.md)\n├── examples/                        # Example flows (auto-published to docs)\n├── formal/                          # Executable formal models (see formal/tla/AGENTS.md)\n├── integration-tests/               # End-to-end integration tests (require running server)\n├── justfile                         # Task runner (just <command>)\n├── load_testing/                    # Load/performance testing\n├── plans/                           # Design/implementation plan documents\n├── pyproject.toml                   # Root package config\n├── schemas/                         # JSON schemas (prefect.yaml, settings)\n├── scripts/                         # Code generation and release scripts\n├── src/\n│   ├── integrations/                # External service integrations (see src/integrations/AGENTS.md)\n│   └── prefect/                     # Core package: SDK, server, CLI (see src/prefect/AGENTS.md)\n├── tests/                           # Test suite, mirrors src/prefect/ (see tests/AGENTS.md)\n├── tools/                           # Build tools\n├── ui/                              # Vue UI (legacy, will be replaced by ui-v2)\n├── ui-v2/                           # React UI rewrite (see ui-v2/AGENTS.md)\n└── uv.lock                          # Lockfile (auto-generated, do not edit manually)\n```\n\n# Essential Commands\n\n```bash\n# Dependencies\nuv sync                                # Install all dev dependencies\njust install                           # Same as above, plus perf group\n\n# Running code\nuv run -s my_script.py                             # Run a script with an editable prefect install\nuv run --extra aws repros/1234.py                  # Run repro needing an integration extra\nuv run --project ./src/integrations/<name> <cmd>   # Run against a local integration from repo root\nprefect server start                               # Start local server\nprefect config view                                # Inspect current configuration\n\n# Testing (see tests/AGENTS.md for full details)\nuv run pytest tests/path.py -k name    # Run specific test\nuv run pytest tests/path.py -x -n4     # Parallel, stop on first failure\n\n# Linting & formatting\nuv run ruff check --fix .              # Lint with auto-fix\nuv run ruff format .                   # Format code\nuv run pre-commit run --all-files      # Run all pre-commit hooks\n\n# Docs (from repo root)\njust docs                              # Start Mintlify dev server at localhost:3000\njust generate-docs                     # Regenerate all doc artifacts\n\n# UI (from repo root)\njust ui-v2                             # Start React dev server at localhost:5173\n\n# Docker\ndocker build -t prefect .                              # Default build (Python 3.11)\ndocker build --build-arg PYTHON_VERSION=3.12 -t prefect .  # Custom Python version\ndocker build --build-arg EXTRA_PIP_PACKAGES=\"prefect-aws\" -t prefect .  # With extras\n```\n\n## Quick Reference\n\n| Component | Path | Tests |\n|-----------|------|-------|\n| Core SDK (flows, tasks, states, deployments) | `src/prefect/` | `tests/` |\n| Flow & task engines (async orchestration) | `src/prefect/flow_engine.py`, `task_engine.py` | `tests/engine/` |\n| Client SDK (schemas, HTTP client) | `src/prefect/client/` | `tests/client/` |\n| Server (API, database, scheduling) | `src/prefect/server/` | `tests/server/` |\n| CLI | `src/prefect/cli/` | `tests/cli/` |\n| Settings | `src/prefect/settings/` | `tests/settings/` |\n| Integrations (`prefect-aws`, `prefect-dbt`, etc.) | `src/integrations/` | per-integration |\n| React UI (replacing Vue `ui/`) | `ui-v2/` | `ui-v2/e2e/` |\n\n## Tech Stack & Tooling\n\n- **Python >=3.11,<3.16** with modern typing (`list[int]`, `T | None`)\n- **FastAPI** for REST APIs\n- **Pydantic v2** for validation\n- **SQLAlchemy 2.0** async ORM\n- **Alembic** for database migrations\n- **PostgreSQL/SQLite** databases\n- **React + TypeScript** for UI (see ui-v2/AGENTS.md)\n- **Ruff** for linting and formatting\n- **Pre-commit** hooks: ruff, codespell, mypy (partial), uv-lock, no-commit-to-branch\n\n## Architecture Overview\n\n- **Three user-facing surfaces**: Python SDK (`@flow`/`@task` decorators), CLI (`prefect` command), REST API (FastAPI server)\n- **Server is the source of truth for flow state transitions** — the flow engine proposes states, and the server's orchestration layer accepts or rejects them. Task state transitions are managed locally by the task engine via `set_state` and communicated through `prefect.task_run.*` events\n- **Two published packages**: `prefect` (full SDK + server) and `prefect-client` (lightweight client subset). `client/` contains the build config that selects which files from `src/prefect/` go into `prefect-client`\n- **Integrations are separate PyPI packages** (`prefect-aws`, `prefect-dbt`, etc.) each with their own version, published independently from `src/integrations/`\n- **Async-first execution model** with sync wrappers — the engines (`flow_engine.py`, `task_engine.py`) are async; sync `@flow`/`@task` functions are run in workers\n\n## Anti-patterns\n\n- **Never bypass the server for flow state transitions** — always go through the orchestration API, even in tests. Task state transitions are managed locally by the task engine by design\n- **Never use `pip install` or `uv pip`** — use `uv` for all dependency management\n- **Never use deferred imports** (imports inside functions) unless required to break circular imports or for optional dependencies\n- **Never commit directly to `main`** — a pre-commit hook enforces this\n- **Never skip pre-commit hooks** (`--no-verify`) — fix the underlying issue instead\n- **Never amend commits** (`--amend`) — create new commits instead\n\n# Development Guidelines\n\n## Make sure you have a Prefect server or Prefect Cloud\n- use `prefect config view` to check your current profile\n- run `prefect server start` in the background if needed\n\n## Code Conventions\n\n- Private implementation details (`_private_method`)\n- No public API changes without approval\n- Use single backticks for inline code references in docstrings, not double backticks\n\n## Testing\n\n- Directory structure mirrors source code\n- Run affected tests after changes: `uv run pytest tests/module/`\n- Tests require deterministic behavior\n- Mock external dependencies\n\n## Formal Protocol Models\n\n- Use TLA+ selectively for bounded concurrent or distributed protocols whose correctness depends on interleavings, retries, duplication, time, or ownership. Prefer ordinary tests for local or sequential behavior.\n- Treat each `formal/tla/<protocol>/README.md` as the authority for its scope, configurations, action-to-code mapping, owner, and review triggers.\n- Before changing mapped behavior, review the model and its deterministic regressions. Update them when the abstraction changes; otherwise state in the PR why it remains valid.\n- A green model validates only its documented abstraction, not Prefect's implementation. Implementation evidence comes from mapped behavior and contract tests.\n\n## Working on Issues\n\n- Read the GitHub issue/PR and comments (`gh issue view`, `gh pr view`) before writing code\n- Understand the scope and intended behavior — ask clarifying questions if unclear\n- Create reproduction scripts in `repros/` directory (create it if needed; add to `.gitignore`)\n- Name files by issue number: `repros/1234.py` (only create one file per issue)\n- Ensure the issue is reproducible before fixing\n- Add unit tests for fixes\n- DO NOT delete files from `repros/` directory after reproducing the issue unless asked\n\n## PR Body Style\n\n- Start with \"closes #1234\" if resolving issue\n- Brief summary: \"this PR {changes}\"\n- Details in `<details>` tag\n- Include relevant links\n\n## Code Review Rules\n\nWhen reviewing changes, read and apply [REVIEW.md](REVIEW.md).\n\n# Project Practices\n\n- All PRs require test coverage for new functionality\n- GitHub issues are used for tracking issues (use the `gh` cli)\n- Dependencies: updates to client-side deps in `pyproject.toml` require parallel changes in `client/pyproject.toml`\n- AGENTS.md always symlinked to CLAUDE.md\n",".claude/skills/document-changes/SKILL.md":"---\nname: document-changes\ndescription: Analyze source code changes on the current branch and identify documentation that is stale, inaccurate, or missing. Use before creating a PR to check if docs need updating, or in CI after merges to main to automatically fix docs. Trigger when the user mentions \"doc changes\", \"docs update\", \"check docs\", \"document changes\", or wants to know if code changes affect documentation.\n---\n\n# Document Changes\n\nAnalyze source code changes to find documentation that is stale, inaccurate, or missing, then either report findings or directly apply fixes.\n\n## Modes\n\n- **Report mode (default, local dev):** Produce a structured report of findings with suggested fixes. Offer to apply them.\n- **Edit mode (CI):** Directly apply fixes to existing doc pages. Do not create entirely new pages — flag those as recommendations in the PR body instead.\n\nThe mode is determined by how the skill is invoked. Local interactive use defaults to report mode. CI sets edit mode via the prompt.\n\n## Prerequisites\n\nBefore making any doc edits, read the write-docs skill at `.claude/skills/write-docs/SKILL.md`. All edits must follow its conventions for tone, components, frontmatter, code blocks, and testing directives.\n\n## Workflow\n\n### 1. Determine the diff\n\nFigure out what changed relative to the base branch:\n\n- **On a feature branch (pre-PR):** diff against main\n  ```bash\n  git diff main...HEAD --name-status\n  git diff main...HEAD -- 'src/prefect/' 'src/integrations/'\n  ```\n- **After a merge to main (CI):** read the diff provided at `/tmp/diff.patch`\n- **Explicit check:** diff against main\n\nFilter the diff to only source code changes. Skip:\n- Test files (`**/tests/**`)\n- CI/workflow files (`.github/`)\n- Documentation files (`docs/`, `*.md`, `*.mdx`)\n- Lock files (`uv.lock`, `package-lock.json`)\n- UI files (`ui-v2/`)\n\n### 2. Extract public API surface changes\n\nScan the diff for changes that users would encounter:\n\n**Function and class signatures:**\n- New, renamed, or removed public functions/classes/methods\n- Changed parameters (added, removed, renamed, retyped)\n- Changed default values\n- Changed return types\n\n**CLI commands:**\n- New, renamed, or removed commands (look for `@app.command()`, click/typer decorators)\n- Changed arguments or options\n- Changed help text\n\n**Configuration and settings:**\n- New, renamed, or removed settings (look for `Setting`, `Field` in settings classes)\n- Changed defaults or validation\n- Changed environment variable names\n\n**Behavioral changes:**\n- Changed error types or messages users would see\n- Changed lifecycle behavior (e.g., retry logic, state transitions)\n- Changed defaults that affect runtime behavior\n\n**Skip:**\n- Private/internal symbols (names starting with `_` in `_internal` modules)\n- Type-only changes that don't affect runtime behavior\n- Import reorganizations that don't change the public API\n- Pure refactors with no behavioral change\n\n### 3. Map changes to existing docs\n\nFor each extracted change, search the docs for references. Use parallel searches for efficiency.\n\n**Exclude auto-generated files.** Before searching or editing, filter out all auto-generated doc files. These are maintained by generation scripts and will be updated separately before each release. Never search, flag, or edit these paths:\n- `docs/v3/api-ref/` — entire directory (generated by `scripts/generate_api_ref.py` and `scripts/generate_settings_ref.py`)\n- `docs/v3/examples/` — entire directory (generated by `scripts/generate_example_pages.py`)\n- Any file containing a comment like `This page is generated by` or `automatically generated`\n\n**Search strategy:**\n- Grep `docs/` (excluding auto-generated paths above) for function names, class names, CLI command names, setting names\n- Check concept pages that explain the changed feature's behavior\n- Check how-to guides that demonstrate the changed API\n- Check get-started pages if fundamental APIs changed\n- Check integration docs if integration entry points changed\n\n**Build a findings list with these categories:**\n\n**Stale — docs describe something that changed:**\n- Wrong default value documented\n- Old parameter name or signature\n- Removed feature still documented\n- Behavior description that no longer matches the code\n- Code examples using old API\n\n**Missing — new public API/feature with no doc coverage:**\n- New public function/class with no mention in any doc page\n- New CLI command not documented\n- New setting not listed in configuration docs\n- New feature that extends an existing documented concept\n\n**Broken examples — code blocks that reference changed APIs:**\n- Code blocks using removed or renamed functions\n- Code blocks with old parameter names\n- Code blocks that would produce different output than described\n\n### 4. Produce output\n\n#### Report mode (local dev)\n\nPrint a structured report grouped by doc file:\n\n```markdown\n## Documentation Changes Report\n\n### `docs/v3/concepts/flows.mdx`\n\n1. **[Stale]** Line 45: `@flow(retries=3)` — `retries` parameter renamed to `max_retries` in src/prefect/flows.py\n   - **Suggested fix:** Update parameter name in code example and surrounding prose\n\n2. **[Broken example]** Line 78-85: Code block uses `flow.run()` which was removed\n   - **Suggested fix:** Replace with `flow()` direct invocation\n\n### `docs/v3/how-to-guides/workflows/retries.mdx`\n\n1. **[Stale]** Line 23: \"Default retry delay is 5 seconds\" — default changed to 10 seconds in this branch\n   - **Suggested fix:** Update to \"Default retry delay is 10 seconds\"\n\n### Missing coverage\n\n1. **[Missing]** New `@flow(on_cancellation=...)` hook added — no docs mention this parameter\n   - **Recommendation:** Add a section to `docs/v3/concepts/flows.mdx` under \"Flow lifecycle hooks\" or create a new how-to guide\n\n### No changes needed\n- `docs/v3/get-started/quickstart.mdx` — references checked, all current\n```\n\nAfter presenting the report, offer:\n- **Apply fixes** — make the suggested edits to existing pages (follow write-docs skill conventions)\n- **Skip** — if the user disagrees with findings or wants to handle manually\n\n#### Edit mode (CI)\n\nDirectly apply fixes for **Stale** and **Broken example** findings on existing pages:\n- Skip any file under an auto-generated path (`docs/v3/api-ref/`, `docs/v3/examples/`) or containing a generated-by comment — do not edit these even if they appear stale\n- Read each affected doc file\n- Make targeted, minimal edits to fix the specific issues\n- Do not rewrite surrounding content\n- Do not change tone, style, or structure beyond what's needed\n- For code blocks, ensure the fix is syntactically valid\n- Add `{/* pmd-metadata: notest */}` only if the fixed code genuinely can't be tested\n\nFor **Missing** coverage findings, do not create new pages. Instead, collect them for the PR body.\n\n### 5. Quality gate (edit mode only)\n\nBefore considering edits complete, verify each change:\n- Follows write-docs tone (second person, active voice, no marketing language)\n- Uses Mintlify components correctly (not markdown admonitions)\n- Preserves existing frontmatter (title, description, keywords)\n- Does not add or remove pages from `docs/docs.json`\n- Code blocks are syntactically valid Python/bash\n- Changes are minimal — only what's needed to fix the finding\n\n### 6. Offer next steps (report mode only)\n\nAfter applying fixes (if the user chose to), mention:\n- Run `just lint` in `docs/` to check Vale style\n- Run markdown tests if code blocks were modified\n- Any missing coverage items that need new content written (suggest using the write-docs skill)\n\n## Important guidelines\n\n- **Be conservative.** Only flag things that are genuinely wrong or missing. A doc page that doesn't mention every parameter is fine — it's stale only if it mentions the *wrong* value or a *removed* thing.\n- **Don't rewrite for style.** If the prose is accurate, leave it alone even if you'd write it differently.\n- **Verify before flagging.** Read both the diff and the current doc file. A grep hit doesn't mean the doc is wrong — read the context.\n- **Respect doc scope.** Not every public API needs docs. Flag missing coverage for features users would reasonably expect to find documented, not for every internal helper that happens to be public.\n- **Minimize blast radius in CI.** Small, targeted fixes only. If a finding requires judgment about page structure or new content, leave it as a recommendation rather than an automated edit.\n- **Don't touch auto-generated pages.** Skip the entire `docs/v3/api-ref/` directory (including `settings-ref.mdx`, Python SDK reference, CLI reference, and REST API reference), the entire `docs/v3/examples/` directory, and any file containing a generated-by comment (e.g., `This page is generated by`). These files are regenerated by scripts before each release and must not be edited manually or by automation.\n- **Check code block test directives.** If you modify a code block, check whether it has `pmd-metadata` directives and preserve them. If you're unsure whether a modified block is testable, mark it `notest` and note why.\n",".claude/skills/write-docs/SKILL.md":"---\nname: write-docs\ndescription: Comprehensive guide for writing and updating Prefect documentation. Use when creating new doc pages, updating existing docs, or working with Mintlify components and code example testing.\n---\n\n# Writing Prefect Documentation\n\nThis guide covers everything needed to write, update, and test Prefect documentation pages. For structural context (directory layout, navigation, links, local dev commands), see `docs/AGENTS.md`.\n\n## Page types\n\nEach section of the docs serves a distinct purpose. Place new content in the right section and match its tone and structure.\n\n### Get Started (`v3/get-started/`)\n\nOnboarding pages for new users. Content should be linear, opinionated, and get the reader to a working result as fast as possible. Use `<Steps>` for sequential instructions and `<Tabs>` to offer Cloud vs. self-hosted paths. Minimize explanation — link to Concepts for deeper understanding.\n\n### Concepts (`v3/concepts/`)\n\nExplain **what** something is and **why** it matters. Concepts pages define Prefect's mental model — flows, tasks, states, deployments, events, work pools, etc. Start with a short code example showing the concept in action, then explain the underlying model, lifecycle, and relationships to other concepts. Link to How-to Guides for step-by-step instructions. Do not provide exhaustive procedural walkthroughs here.\n\n### How-to Guides (`v3/how-to-guides/`)\n\nTask-oriented pages that show **how** to accomplish a specific goal. Each page should solve one problem (e.g., \"How to write and run a workflow\", \"How to set up retries\"). Structure as a series of actionable steps with code examples. Meet the reader where they are — do not assume familiarity with Prefect internals. Use the smallest amount of Prefect-specific jargon possible, and explain or link terms when they are unavoidable.\n\nGuides are organized into the following categories:\n\n- **`workflows/`** — Writing, running, and customizing flows and tasks: retries, caching, concurrency, logging, testing, runtime info, state hooks, and artifacts.\n- **`deployments/`** — Creating, scheduling, running, and versioning deployments, including `prefect.yaml` configuration and flow code storage.\n- **`deployment_infra/`** — Running workflows on specific infrastructure: Docker, Kubernetes, serverless platforms (AWS ECS, Azure ACI, GCP Cloud Run), Modal, Coiled, Prefect Managed, and local processes. Also covers work pool management.\n- **`automations/`** — Setting up event-driven automations: creating automations and triggers, chaining deployments via events, custom notifications, and accessing event payloads in flows.\n- **`cloud/`** — Prefect Cloud-specific operations: connecting to Cloud, managing workspaces and users, creating webhooks, and troubleshooting.\n- **`configuration/`** — Configuring the Prefect environment: managing settings, storing secrets, and using variables.\n- **`ai/`** — Using Prefect with AI tooling, such as the Prefect MCP server.\n- **`migrate/`** — Upgrading from older Prefect versions or migrating from other tools like Airflow.\n- **`self-hosted/`** — Running the Prefect server yourself via Docker Compose, the CLI, or on Windows.\n\n### Advanced (`v3/advanced/`)\n\nIn-depth pages for experienced users covering topics like transactions, interactive workflows, infrastructure-as-code, scaling self-hosted deployments, and custom API integrations. These assume familiarity with core concepts and how-to patterns. They can be longer and more detailed than how-to guides.\n\n### Examples (`v3/examples/`)\n\n**Auto-generated — do not edit directly.** Each page is generated from a standalone Python file in the repo's top-level `examples/` directory by `generate_example_pages.py`. To add an example, create a new `.py` file in `examples/` with YAML frontmatter in comments and run `just generate-examples`. See `contribute/docs-contribute.mdx` for the full process.\n\n### Integrations (`integrations/`)\n\nEach integration (e.g., `prefect-aws`, `prefect-gcp`) has its own subdirectory. The `index.mdx` covers installation, credential setup (blocks), and key capabilities. Additional pages cover specific workers, tasks, or SDK reference. Follow the existing pattern: \"Why use it\" section, prerequisites, install instructions, blocks setup, then per-service usage sections.\n\n### API Reference (`v3/api-ref/`)\n\n**Auto-generated — do not edit directly.** Covers the Python SDK (`python/`), CLI commands (`cli/`), and REST API (`rest-api/`). CLI pages use `<ResponseField>` and `<Accordion>` components for arguments and options.\n\n### Release Notes (`v3/release-notes/`)\n\nChangelogs organized by product surface: `oss/` for open-source releases, `cloud/` for Prefect Cloud, `integrations/` for integration packages.\n\n### Contribute (`contribute/`)\n\nGuides for contributors: how to set up the dev environment, write docs, develop integrations, and follow code style conventions.\n\n## Adding vs. updating content\n\n### When to update an existing page vs. create a new one\n\n- **Update an existing page** when the new content is a variation, option, or closely related technique for something the page already covers. For example, a new retry strategy belongs on the existing retries page, not a new page.\n- **Create a new page** when the content addresses a distinct goal that doesn't fit naturally into any existing page. A good test: if the page title would need to become vague or a compound sentence to accommodate the new content, it deserves its own page.\n- When in doubt, prefer extending an existing page. Fewer, more comprehensive pages are easier for readers to discover than many small, fragmented ones.\n\n### When to add a new category or section\n\n- **Create a new subdirectory** only when you have multiple pages (or a clear roadmap for multiple pages) that share a theme not covered by any existing category. A single page does not justify a new category — place it in the closest existing one.\n- Before creating a category, check whether the content fits in an existing one. For example, a guide about running flows on a new cloud platform belongs in `deployment_infra/`, not a new category named after that platform.\n- New categories must also be added as a group in the `navigation.tabs` section of `docs/docs.json`, with an `index.mdx` page for the group overview.\n\n## Page templates\n\nStarter templates live in this skill directory. Copy one as the basis for a new page and fill in the bracketed placeholders:\n\n- **How-to guide** — `template-howto.mdx`\n- **Concept page** — `template-concept.mdx`\n\nAdjust headings and sections to fit the content — the templates show the expected shape, not a rigid format.\n\n### Keywords for searchability\n\nEvery page should include a `keywords` array in its frontmatter. Keywords feed Mintlify's search index and help readers find pages using terms that don't appear in the title or description.\n\n```yaml\nkeywords: [\"retry\", \"retries\", \"error handling\", \"fault tolerance\"]\n```\n\n- Include 3-5 lowercase terms a reader might search for.\n- Use synonyms and shorthand readers would actually type (e.g., \"k8s\" is wrong in prose but useful as a keyword alongside \"Kubernetes\").\n- Don't repeat words already in `title` or `description` — those are indexed automatically.\n\n## Registering pages in navigation\n\nEvery new page must be added to `docs/docs.json` under `navigation.tabs` or it won't appear in the sidebar. Add the page path (without `.mdx`) to the appropriate group:\n\n```json\n{\n  \"tab\": \"How-to Guides\",\n  \"pages\": [\n    \"v3/how-to-guides/index\",\n    {\n      \"group\": \"Workflows\",\n      \"pages\": [\n        \"v3/how-to-guides/workflows/write-and-run\",\n        \"v3/how-to-guides/workflows/retries\"\n      ]\n    }\n  ]\n}\n```\n\n- Each tab has a `\"tab\"` display name and either `\"pages\"` or `\"groups\"`.\n- Groups can nest: a group's `\"pages\"` array can contain strings (page paths) or nested `{\"group\": ..., \"pages\": [...]}` objects.\n- Place new pages at a logical position within the existing group — typically at the end, unless ordering matters for the reader.\n\n## Mintlify components\n\nUse these components (not standard Markdown admonition syntax):\n\n```mdx\n<Note>Important information.</Note>\n<Warning>Caution about potential issues.</Warning>\n<Tip>Helpful suggestion.</Tip>\n<Info>Additional context.</Info>\n\n<Accordion title=\"Expandable section\">\n  Content hidden until clicked.\n</Accordion>\n\n<Tabs>\n  <Tab title=\"Option A\">Content for A</Tab>\n  <Tab title=\"Option B\">Content for B</Tab>\n</Tabs>\n\n<Steps>\n  <Step title=\"First step\">Instructions</Step>\n  <Step title=\"Second step\">Instructions</Step>\n</Steps>\n\n<CardGroup cols={3}>\n  <Card title=\"Title\" icon=\"icon\" href=\"/v3/path\">\n    Description text.\n  </Card>\n</CardGroup>\n\n<CodeGroup>\n```bash pip\npip install prefect\n```\n```bash uv\nuv pip install prefect\n```\n</CodeGroup>\n```\n\n## Reusable snippets\n\nSnippets live in `snippets/` and are imported with JSX:\n\n```mdx\nimport ComponentName from '/snippets/path.mdx'\n\n<ComponentName />\n```\n\nAlways check for an existing snippet before writing duplicate content. Key snippets to know about:\n\n- `snippets/installation.mdx` — Standard Prefect install instructions (used in `v3/get-started/install.mdx`). Use this instead of writing ad-hoc install blocks.\n- `snippets/resource-management/` — Consistent \"manage this resource via CLI / API / Terraform / Helm\" callouts. Import the relevant variant when documenting a Prefect resource.\n\n## Code blocks\n\nCode blocks support language hints, filenames, line highlighting, and expandable sections:\n\n````mdx\n```python my_flow.py\nfrom prefect import flow\n\n@flow\ndef hello():\n    print(\"Hello!\")\n```\n\n```bash {3} [expandable]\nprefect deploy --all\nprefect work-pool create my-pool --type process\nprefect worker start --pool my-pool\n```\n````\n\nMark code blocks that should **not** be tested with the comment `{/* pmd-metadata: notest */}` on the line before the code block.\n\nPrefer minimal, runnable snippets that produce a visible result (printed output, a return value, or a logged message). Avoid placeholder names like `foo`/`bar` in user-facing examples — use realistic names that reflect the domain (e.g., `process_order`, `customer_id`).\n\n## Code example testing\n\nPython code blocks in `.mdx` files are automatically extracted and executed as tests using [pytest-markdown-docs](https://github.com/modal-labs/pytest-markdown-docs). Tests run in CI against a live Prefect server and are parallelized with pytest-xdist (up to 6 workers). All test configuration — fixtures, skip lists, and injected globals — lives in `docs/conftest.py`.\n\n### How it works\n\nBy default, every fenced Python code block in an `.mdx` file is treated as an independent test. The plugin extracts the block, executes it, and fails if it raises an exception. Each block runs in its own namespace unless `continuation` is used (see below).\n\n### Running tests locally\n\nThere is no `just` command for markdown tests. Run them manually:\n\n```bash\n# Start a Prefect server in the background\nPREFECT_HOME=$(pwd) uv run prefect server start &\n\n# Run the markdown doc tests\nPREFECT_API_URL=\"http://127.0.0.1:4200/api\" uv run --group markdown-docs pytest docs/ -m markdown-docs\n```\n\n### pmd-metadata directives\n\nControl test behavior with `{/* pmd-metadata: <directive> */}` comments placed on the line immediately before a code fence.\n\n**`notest`** — Skip this code block entirely. Use when code is illustrative, incomplete, or requires setup that cannot be provided in the test environment.\n\n```mdx\n{/* pmd-metadata: notest */}\n```python\n# This block will not be tested\nprefect deploy --some-hypothetical-flag\n```\n```\n\n**`continuation`** — Share state (imports, variables, function definitions) from preceding code blocks on the same page. Without this, each block starts with a clean namespace. Use when a multi-step example is split across blocks for readability.\n\n```mdx\n```python\nfrom prefect import flow\n\n@flow\ndef my_workflow() -> str:\n    return \"Hello, world!\"\n```\n\n{/* pmd-metadata: continuation */}\n```python\nmy_workflow()  # Can reference the function defined above\n```\n```\n\n**`fixture:<name>`** — Inject a pytest fixture defined in `conftest.py` as a global in the code block. Use when a block needs mocking (e.g., HTTP calls).\n\n```mdx\n{/* pmd-metadata: fixture:mock_post_200 */}\n```python\nimport requests\nresponse = requests.post(endpoint, headers=headers, json=data)\nassert response.status_code == 200\n```\n```\n\n### Global imports\n\nThe `pytest_markdown_docs_globals` hook in `conftest.py` injects a small set of globals into every code block automatically: `Mapped`, `Run`, `Union`, `mapped_column`, `sa`. You do not need to import these in doc examples.\n\n### Autouse fixtures\n\nTwo fixtures are applied to every test automatically (defined in `conftest.py`):\n\n- `mock_runner_start` — Mocks `prefect.cli.flow.Runner.start` so flow-serving examples don't actually start a long-running process.\n- `mock_base_worker_submit` — Mocks `BaseWorker.submit` and `KubernetesWorker.submit` so worker examples don't attempt real infrastructure calls.\n\n### Skipped files\n\nSome files are skipped entirely via the `SKIP_FILES` dict in `conftest.py`. Common reasons include needing database fixtures, block cleanup, live network calls, or async contexts. Additionally:\n\n- All files under `v3/api-ref/python/` are auto-skipped (generated reference docs).\n- All files under `v3/examples/` are auto-skipped (tested separately in their source repo).\n\nWhen adding a new page that genuinely cannot be tested, add it to `SKIP_FILES` with a reason rather than marking every block with `notest`.\n\n## Images\n\nPlace images in `v3/img/` organized by section (e.g., `v3/img/ui/`, `v3/img/concepts/`). Reference them with absolute paths:\n\n```mdx\n![Description](/v3/img/ui/screenshot.png)\n```\n\n- Always include meaningful alt text that describes what the image shows.\n- Use compressed PNG or WebP format to keep page load times fast.\n- Avoid committing unnecessarily large screenshots; crop to the relevant area.\n\n## Linting\n\nDocs are linted with [Vale](https://vale.sh/) using Google style, Vale defaults, and custom Prefect rules. Run locally:\n\n```bash\njust lint\n```\n\nOr manually: `vale --glob='**/*.{md,mdx}' .`\n\n## Tone and style\n\n- Use second person (\"you\") and active voice in present tense.\n- Avoid first person (\"I\", \"we\") and marketing language (\"powerful\", \"seamless\", \"best-in-class\").\n- Be direct and concise. Shorter sentences are easier to scan.\n- Follow the [Google developer documentation style guide](https://developers.google.com/style) as the baseline.\n\nExamples of preferred phrasing:\n\n| Instead of | Write |\n|---|---|\n| \"We recommend configuring...\" | \"Configure...\" |\n| \"You'll want to make sure to...\" | \"Make sure to...\" or just state the instruction |\n| \"This powerful feature allows you to...\" | \"Use [feature] to...\" |\n| \"I'll show you how to set up...\" | \"To set up..., do the following:\" |\n| \"It should be noted that...\" | State the fact directly |\n| \"In order to\" | \"To\" |\n\nWhen introducing a concept, lead with what the reader can *do*, not what the feature *is*:\n\n- Before: \"The retry mechanism is a configurable system that allows flows to recover from transient failures.\"\n- After: \"Add retries to your flow to recover automatically from transient failures.\"\n\n## Quality checklist\n\nBefore considering a page complete, verify:\n\n1. The page opens with appropriate context: for how-to guides, a single-sentence scope line (or jump straight into steps if the title already establishes the goal); for concepts and advanced pages, an opening paragraph that defines the topic and why it matters.\n2. Prerequisites (tools, access, prior knowledge) are called out up front.\n3. The page includes at least one cross-link to a related Concept or How-to page.\n4. All code blocks are runnable and tested, or explicitly marked with `{/* pmd-metadata: notest */}` with a reason.\n5. Frontmatter includes `keywords` with 3-5 search terms not already in the title or description.\n6. The page is registered in `docs/docs.json` navigation.\n\n## Common mistakes\n\n- Using `#` (H1) in the body — the frontmatter `title` already renders as H1.\n- Using relative links or including `.mdx` in link paths.\n- Using Markdown admonitions (`> **Note:**`) instead of Mintlify components (`<Note>`).\n- Inconsistent heading hierarchy (jumping from H2 to H4).\n- Missing `description` or `keywords` in frontmatter — both improve search discoverability.\n- First-person pronouns (\"I\", \"we\") — use \"you\" or imperative voice.\n- Wrong terminology casing: \"Prefect cloud\" (should be \"Prefect Cloud\"), \"Prefect Server\" (should be \"Prefect server\"), \"k8s\" (should be \"Kubernetes\"), \"infra\" (should be \"infrastructure\").\n- Forgetting to register a new page in `docs/docs.json` — the page won't appear in nav.\n- Forgetting to add a redirect in `docs/docs.json` when moving or renaming a page.\n- Overusing `<Note>`/`<Tip>`/`<Warning>` — reserve for genuinely important callouts, not every paragraph.\n","integration-tests/AGENTS.md":"# Integration Tests\n\nEnd-to-end tests that require a live Prefect server and verify the full orchestration pipeline across process boundaries.\n\n## Purpose & Scope\n\nThese tests cover scenarios that unit tests cannot: real server ↔ worker communication, subprocess flow execution, cancellation across process boundaries, event delivery, and scheduling statefulness.\n\nThey do NOT duplicate unit tests in `tests/`. If a behavior can be tested in isolation, it belongs there.\n\n## Running\n\n```bash\n# Integration tests are excluded from the default testpaths in pyproject.toml — they will NOT run with uv run pytest tests/\nuv run pytest integration-tests/\nuv run pytest integration-tests/test_nested_cancellation.py\n```\n\nRequirements:\n- `PREFECT_API_URL` must point to a running Prefect server (check with `prefect config view`)\n- `uv` must be available in `PATH`\n\nSome tests accept additional env vars: `SERVER_VERSION` (skip version-specific tests), `PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE`, `PREFECT_API_AUTH_STRING`.\n\n## Structure\n\nNo shared `conftest.py`. Each test file is self-contained with its own helpers and fixtures inline. There are no pytest fixtures shared across files.\n\n## Usage Patterns\n\n**Poll, don't assert synchronously.** Hook execution, state transitions, and marker-file writes are independent side effects of the same cancel/complete sequence — the API state can become visible before the hook's file is written. Use `_wait_for()` instead of a bare `assert`:\n\n```python\n# Wrong — races on rare timing:\nassert Path(marker_dir, HOOK_MARKER).exists()\n\n# Right — polls until satisfied or timeout:\n_wait_for(\n    lambda: Path(marker_dir, HOOK_MARKER).exists(),\n    timeout=30,\n    message=\"Hook did not write its marker.\\n\" + _worker_output(log_path),\n)\n```\n\n**Marker files for cross-process state.** Flows running in subprocesses write files to a shared `tmp_path` to signal that a state was reached. Name markers with constants (`PARENT_HOOK_MARKER`, `CHILD_STARTED_MARKER`, etc.) and document them at the top of the file.\n\n**Subprocess invocations use `uv --isolated`.** All CLI calls go through `uv.find_uv_bin()` with `--isolated` to get a clean environment:\n\n```python\nsubprocess.run([uv.find_uv_bin(), \"run\", \"--isolated\", \"prefect\", \"worker\", \"start\", ...])\n```\n\n`PREFECT_API_URL` is inherited from the calling process's env — it still needs to be set.\n\n**Unique work pool names.** Always suffix with `uuid4()` to avoid conflicts across parallel test runs.\n\n**Explicit cleanup in `finally`.** Deployments, work pools, and subprocesses must be cleaned up manually — there is no pytest fixture teardown:\n\n```python\ntry:\n    # set up pool, deployment, worker, run assertions\nfinally:\n    client.delete_work_pool(pool_name)\n    proc.terminate()\n    try:\n        proc.wait(timeout=5)\n    except subprocess.TimeoutExpired:\n        proc.kill()\n```\n\n## Anti-Patterns\n\n- Don't assert synchronously on hook markers or other side effects right after triggering a cancellation — always poll.\n- Don't use fixed `asyncio.sleep()` delays as a substitute for `_wait_for()` — they either waste time or still race.\n- Don't share state between test files via module-level globals — each file is standalone.\n- Don't use subprocess CLI for infrastructure setup/teardown (work pool CRUD, deployment creation) — use `get_client(sync_client=True)` API calls instead. Subprocess is only for testing cross-process behavior (starting workers, executing flow runs in a separate process).\n\n## Pitfalls\n\n- `PREFECT_API_URL` not set produces cryptic errors, not a helpful configuration message. Check it first.\n- These tests are slow (seconds to minutes per test) and intentionally excluded from the default `testpaths` in `pyproject.toml`.\n- Process `terminate()` sends SIGTERM but the subprocess may not exit immediately — always `wait(timeout=...)` and fall back to `kill()`.\n- WebSocket event subscriptions are not active until the `async with get_events_subscriber(...)` context establishes the server connection — events emitted before that happens are silently lost. Signal readiness from *inside* the subscription context using a `threading.Event`, and `assert ready.wait(timeout=30)` before triggering any events in the test.\n","docs/AGENTS.md":"# Prefect Documentation\n\nStructural context for any agent working in `docs/`. For the full writing guide (page types, components, code testing, style), use the `/write-docs` skill.\n\n## Platform\n\n[Mintlify](https://mintlify.com/) docs published to [docs.prefect.io](https://docs.prefect.io). All files use `.mdx` (Markdown + JSX). Site config lives in `docs/docs.json`.\n\n## Directory structure\n\n```\ndocs/\n  v3/                     # Primary docs for Prefect 3.x\n    get-started/          # Installation, quickstart\n    concepts/             # Core concepts (flows, tasks, states, deployments, etc.)\n    how-to-guides/        # Practical guides organized by category\n    advanced/             # Advanced topics\n    examples/             # Auto-generated from examples/ Python files — do NOT edit directly\n    api-ref/              # API reference — mix of auto-generated and hand-authored\n      python/             # SDK reference (auto-generated — do NOT edit directly)\n      cli/                # CLI command reference (auto-generated — do NOT edit directly)\n      rest-api/           # REST API docs (server/ and cloud/) — endpoint pages auto-generated; index.mdx overview pages are hand-authored\n      events/             # Events reference catalog — hand-authored, editable\n    release-notes/        # Version release notes\n    img/                  # Images organized by section\n  integrations/           # Integration-specific docs (prefect-aws, prefect-gcp, etc.)\n  contribute/             # Contributor guides\n  snippets/               # Reusable MDX snippets imported across pages\n  images/                 # Legacy images\n  logos/                  # Brand assets\n  styles/                 # Vale linting styles\n  resources/              # Unlisted pages (hidden: true) outside the v3/ versioning tree\n```\n\n## Auto-generated content — do not edit\n\n- `v3/examples/` — generated from top-level `examples/` Python files by `generate_example_pages.py`\n- `v3/api-ref/python/`, `v3/api-ref/cli/` — generated API reference (Python SDK, CLI)\n- `v3/api-ref/rest-api/` — individual endpoint pages are auto-generated; the `index.mdx` files at `rest-api/` and `rest-api/server/` are hand-authored and may be edited\n- `v3/api-ref/events/` is **hand-authored** and should be edited directly when event schemas change\n- `integrations/<name>/api-ref/` — generated per-integration API reference via `mdxify` (e.g., `integrations/prefect-kubernetes/api-ref/`); regenerated on each integration release\n\n## File format\n\nEvery `.mdx` file starts with YAML frontmatter:\n\n```yaml\n---\ntitle: Page Title\ndescription: Brief description for SEO and navigation\nsidebarTitle: Optional shorter sidebar label   # optional\nicon: icon-name                                # optional, Mintlify icon\nmode: wide                                     # optional; use \"custom\" for raw JSX/HTML layouts\nhidden: true                                   # optional; unlisted page — no nav registration needed\nkeywords: [\"keyword1\", \"keyword2\"]             # optional, for search\n---\n```\n\nFrontmatter keys are always lowercase. The `title` renders as the page's H1, so start body content at `##` — do not add another H1.\n\n## Navigation\n\nAll pages must be registered in `docs/docs.json` under `navigation.tabs`. When adding a page, add its path (without `.mdx` extension) to the appropriate group.\n\n## Links\n\nUse absolute paths from the docs root without `.mdx`:\n\n```mdx\nSee the [flows documentation](/v3/concepts/flows) for details.\n```\n\nDo not use relative paths or include `.mdx` in links.\n\n## Redirects\n\nWhen renaming or moving a page, add a redirect in `docs/docs.json` `redirects` array so existing links continue to work. Never remove existing redirects unless you are certain the old URL has no inbound traffic. Paths should not include `.mdx`.\n\n## Terminology and casing\n\nPreferred terms are enforced by Vale via `docs/styles/CustomStyles/WordList.yml`. Key entries:\n\n- \"Prefect Cloud\" (not \"Prefect cloud\")\n- \"Prefect server\" (not \"Prefect Server\")\n- \"infrastructure\" (not \"infra\")\n- \"Kubernetes\" (not \"k8s\")\n- \"open source\" (not \"open-source\")\n\n## Versioning\n\nAll new content goes in `docs/v3/`. Do not create pages outside `v3/` for current Prefect 3.x features. Exception: unlisted pages (`hidden: true`) can live in `docs/resources/`.\n\n## Local development\n\n```bash\njust docs     # Start the dev server at localhost:3000\njust links    # Check for broken links\njust lint     # Run Vale linter\n```\n\n## Key rules\n\n1. **Do not edit auto-generated files.** Pages under `v3/examples/`, `v3/api-ref/python/`, `v3/api-ref/cli/`, `v3/api-ref/rest-api/`, and `integrations/<name>/api-ref/` are generated from source code. The exception is `v3/api-ref/events/`, which is hand-authored and should be edited when event schemas change.\n2. **Register new pages in `docs/docs.json`.** An unregistered page won't appear in navigation. Exception: pages with `hidden: true` are unlisted and do not require navigation registration.\n3. **Use `.mdx` extension** for all new documentation files.\n4. **Use Mintlify components** (`<Note>`, `<Tabs>`, `<Steps>`, etc.) rather than Markdown-native admonition syntax.\n5. **Keep code examples working.** They are tested in CI via `pytest-markdown-docs`. Two skip mechanisms exist:\n   - Per-block: add `{/* pmd-metadata: notest */}` above the fenced code block when a single example can't run in isolation.\n   - Per-file: add the path to `SKIP_FILES` in `docs/conftest.py` when an entire page requires real external infrastructure (a live database, a dbt project and profiles, real API credentials). Integration pages almost always fall into this category.\n6. **Use absolute link paths** without file extensions (e.g., `/v3/concepts/flows`).\n7. **Check for existing snippets** in `snippets/` before duplicating content.\n8. **Start body content at `##`.** The frontmatter `title` renders as H1; do not add another H1 in the body.\n9. **Document and mark Cloud-only features.** Some features are only available in Prefect Cloud and have no open source equivalent (SSO, audit logs, incidents, SLAs, the `send-email-notification` automation action, etc.). These originate in the `nebula` repo, so they are documented by Prefect staff and agents rather than external contributors. Make sure they are documented here and marked so customers and downstream consumers (such as the Terraform provider and SDKs) can discover them. Conventions:\n   - **Where Cloud-only guides live.** Account, workspace, and user management guides live under `v3/how-to-guides/cloud/`. Prefer this location for new Cloud-only how-to content.\n   - **Mark the feature** when it appears on a page that also covers open source behavior (for example a shared concept page), so readers can tell the editions apart. Use one of:\n     - A Cloud badge on its own line, directly above the page or section it marks: `<span class=\"badge cloud\"></span>`. It renders a standalone \"Prefect Cloud\" label and the span is intentionally empty; put a blank line before the following prose so it scopes the whole section rather than a single sentence.\n     - A `<Note>This action is only available in Prefect Cloud.</Note>` callout for inline cases (e.g. a single table row or variable).",".claude/commands/repro.md":"---\ndescription: Reproduce a bug in the Prefect codebase.\nargument-hint: \"[the gh issue link or issue number]\"\n---\n\nuse `gh` to read and understand the following github issue: $1.\n\nRead the body and all comments in the issue.\n\nbefore reproducing, `rg` for documentation in `docs/` that may be relevant to the issue.\n\nif a `repros/` directory already exists (it will be locally gitignored), `rg` for relevant SDK usage to gain context.\n\n\nTo reproduce, create a file named by issue number (ie. `1234.py`) in a locally gitignored (.git/info/exclude) `repros/` directory with a minimal reproducible example that reproduces the issue. Because `repros/` is gitignored, you should NEVER reference it in a PR body, instead put the entire reproduction script in a python snippet inside a `<details>` tag.\n\nIf the reproduction requires external dependencies, use `uv` to inline script dependencies to install them like this:\n\n```\n# ///script\n# dependencies = [\"pandas\", \"numpy\"]\n# ///\n\n# rest of script\n```\nand then invoke the script with `uv run --with-editable . repros/1234.py` to use the editable copy of Prefect along with the external dependencies.\n\nReview the actual `prefect` library in `src/prefect` (or integration in `src/integrations`) to ensure that the reproduction is aware of the implementation details of the code.\n",".claude/skills/write-docs/template-concept.mdx":"---\ntitle: [Concept name]\ndescription: [One sentence explaining what this concept does.]\nkeywords: [\"keyword1\", \"keyword2\", \"keyword3\"]\n---\n\n{/*\n  keywords: Include 3-5 lowercase terms a reader might search for.\n  Use synonyms and abbreviations readers would type — e.g., for a\n  flows page: [\"flow\", \"workflow\", \"orchestration\", \"decorator\"].\n  Don't repeat words already in the title or description.\n*/}\n\n```python\nfrom prefect import flow\n\n@flow\ndef my_flow():\n    return \"Hello!\"\n\nmy_flow()\n```\n\n## What is [concept]?\n\nExplain the concept and why it matters.\n\n## [Key aspect or behavior]\n\nDeeper explanation with examples.\n\n<Tip>\nCall out a key detail the reader should remember.\n</Tip>\n\n## Next steps\n\n- [How to do X with this concept](/v3/how-to-guides/category/guide)\n","ui-v2/AGENTS.md":"# Prefect UI v2 - React Migration\n\nThis is the new React-based Prefect UI, migrating from the legacy Vue application with minimal visual and functional changes.\n\n## Project Structure\n\n```\nprefect/ui-v2/\n├── src/\n│   ├── api/           # API queries, mutations, and mocks\n│   ├── auth/          # Authentication state, AuthProvider, useAuth hook\n│   ├── components/    # React components organized by domain\n│   ├── graphs/        # Pixi.js run graph rendering engine (ported from @prefecthq/graphs)\n│   ├── hooks/         # Custom hooks for common patterns\n│   ├── lib/           # Utility functions and shared code\n│   ├── mocks/         # Mock data factories\n│   ├── routes/        # Tanstack Router route definitions\n│   ├── storybook/     # Storybook utilities and decorators\n│   └── utils/         # Helper functions and utilities\n├── tests/             # Test utilities and configuration\n├── .storybook/        # Storybook configuration\n└── public/            # Static assets\n```\n\n## Tech Stack\n\n- **React** with TypeScript\n- **Tailwind CSS** - styling\n- **shadcn/ui** - UI component library\n- **Tanstack Query** - API state management\n- **Tanstack Router** - routing\n- **Tanstack Table** - table state management\n- **react-hook-form** - form state management\n- **Recharts** - charts and data visualization\n- **Pixi.js** - WebGL canvas rendering for run graphs (`src/graphs/`)\n- **Vitest** - testing framework\n- **Storybook** - component development and documentation\n- **MSW** - API mocking\n\n## General Principles\n\n- Prefer using functionality from third party libraries over custom implementations\n- Prefer to colocate components in the same file as long as the file is less than 750 lines\n\n## Development Workflow\n\n### Development Process\n\n1. **Start development server**: `npm run dev` (runs on http://localhost:5173/)\n2. **Write tests first** for new components and hooks before implementation\n3. **Implement** the component/hook following existing patterns\n4. **Create Storybook story** to document component variants\n5. **Verify functionality** in the browser at http://localhost:5173/\n6. **Compare with legacy Vue** implementation at http://localhost:4200/ for consistency\n\n### Pre-commit Checklist\n\nBefore committing any changes, always run:\n\n1. **Format and lint**: `npm run check` (Biome formatting and linting)\n2. **Additional linting**: `npm run lint` (ESLint rules)\n3. **Build verification**: `npm run build` (ensure no build errors)\n4. **Test verification**: `npm test` (run relevant tests)\n\n### Performance Tips\n\n- Run **single tests** for faster feedback: `npm test -- ComponentName`\n- Run **lint on single files** for performance: `npx eslint src/path/to/file.ts --fix`\n- Use **Storybook** for isolated component development: `npm run storybook`\n\n### Browser Testing\n\n- **Primary development**: http://localhost:5173/\n- **Legacy comparison**: http://localhost:4200/\n- **Component documentation**: http://localhost:6006/ (Storybook)\n\n## Common Commands\n\n- `npm run dev` - Start development server\n- `npm run build` - Build production bundle\n- `npm run test` - Run tests\n- `npm run check` - Run linter and formatter (Biome)\n- `npm run lint` - Run ESLint\n- `npm run storybook` - Start Storybook\n- `npm run service-sync` - Sync API types from backend\n\n## Code Organization\n\n- **Flat structure**: Components, tests, and stories live together\n- **Index exports**: Each directory exports public APIs via `index.ts`\n- **Domain organization**: Components organized by Prefect domain (flows, deployments, etc.)\n- **Namespace awareness**: Component names consider their directory context\n\n## Quality Standards\n\n- **Always write tests** for new components and hooks\n- **Always create Storybook stories** for new components\n- **Run `npm run check`** after creating components/hooks\n- **Check functionality** in browser during development\n- **Mock all API calls** using MSW\n\n## API Integration\n\n- Use **`useSuspenseQuery`** over `useQuery` for declarative code; use `useQuery` when the component must silently return `null` while loading rather than suspend the tree (e.g., optional or promotional components that should disappear rather than show a skeleton)\n- **Query factories** in `/api` directories with standardized key patterns\n- **Mutation hooks** in `/api` directories\n- **No data transformation** in query factories - do it in components\n- **Duration fields** (`estimated_run_time`, `total_run_time`, etc.) are returned in **seconds** by the API. Prefer `secondsToApproximateString`/`secondsToString` from `@/utils/seconds` for display — they take raw seconds directly. `humanizeDuration` and similar JS libraries expect milliseconds instead, so multiply by 1000 before passing to them\n\n## Forms\n\n- **react-hook-form** for form state\n- **zod** for validation\n- **Form** and **FormField** components from shadcn/ui\n- **Stepper** component for wizard flows\n- **Forms bound to refetched queries**: Entity queries (deployments, etc.) refetch on a 30-second interval and on window focus, returning new object references each time. Use `useState` lazy initializers to capture default values once — do not sync form state via `useEffect`, which overwrites in-flight user edits on every refetch. Add `key={entity.id}` on the form component so it fully resets when the entity changes.\n- **Zod v4**: `z.record()` requires an explicit key schema — `z.record(z.string(), z.unknown())`, not the v3-style `z.record(z.unknown())`. `ZodError` instances expose `.issues`, not the removed `.errors`.\n\n## Testing\n\n- **Vitest** with **@testing-library/react**\n- All API calls mocked with **MSW**\n- Mock factories using **@ngneat/falso**\n- Run single tests for performance: `npm test -- ComponentName`\n\n## Git Workflow\n\n- Branch naming: `ui-v2/feature-description`\n- Succinct commit messages\n- PR descriptions mention \"Related to #15512\"\n- Never commit directly to `main`\n\n## Styling for Light and Dark Mode\n\nThe UI supports both light and dark themes. To ensure components render correctly in both modes:\n\n### Use Semantic Color Tokens\n\nAlways use Tailwind's semantic color classes that automatically adapt to the current theme instead of hardcoded color values:\n\n| Instead of | Use |\n|------------|-----|\n| `bg-gray-100`, `bg-gray-200` | `bg-muted` |\n| `bg-white` | `bg-background` or `bg-card` |\n| `text-gray-500`, `text-gray-600` | `text-muted-foreground` |\n| `text-gray-900`, `text-black` | `text-foreground` |\n| `border-gray-200`, `border-gray-300` | `border-border` or `border-muted` |\n\n### For Dividers and Subtle Elements\n\nUse opacity modifiers with semantic colors for subtle visual elements like dividers:\n- `bg-muted-foreground/30` for subtle divider lines\n- `border-border` for standard borders\n\n### Prose Content in Dark Mode\n\nTailwind's `prose` class (`@tailwindcss/typography`) does **not** automatically invert in dark mode. Any element using `prose` must also include `dark:prose-invert`:\n\n```tsx\n<div className=\"prose dark:prose-invert\">...</div>\n```\n\n### CodeMirror Editors\n\n`@uiw/react-codemirror` does not follow the app theme automatically. Any component using `useCodeMirror` must explicitly read and pass the theme:\n\n```tsx\nconst { resolvedTheme } = useTheme(); // from \"next-themes\"\nuseCodeMirror({ theme: resolvedTheme === \"dark\" ? \"dark\" : \"light\", ... });\n```\n\n### Avoid Hardcoded Colors\n\nNever use hardcoded gray scale colors (e.g., `bg-gray-100`, `text-gray-500`) as these will not adapt to dark mode and can make text unreadable or create jarring visual contrast.\n\n### Testing Dark Mode\n\nAlways verify components in both light and dark mode:\n1. Use the theme toggle in Settings to switch between modes\n2. Check that all text remains readable\n3. Verify backgrounds blend appropriately with the overall theme\n4. Ensure sufficient contrast for interactive elements\n\n## Architecture Notes\n\n- **Suspense-first**: Use suspense queries to avoid loading states\n- **Type safety**: Never use `as unknown` or disable ESLint\n- **Pure functions**: Keep utilities side-effect free\n- **Composition**: Prefer composition over complex inheritance\n","tests/AGENTS.md":"# Test Suite\n\nTests for all Prefect components. Directory structure mirrors `src/prefect/`.\n\n## Key Contracts\n\n- **Server and client test fixtures should not mix.** Server-side tests use a stripped-down client. Do not use `prefect_client` (the full client fixture) in server tests.\n- **Prefer real operations over mocks.** Use real flows, deployments, and flow runs where possible. Reserve `unittest.mock` for external services and time-sensitive operations.\n- **Tests must be deterministic.** No reliance on timing, ordering, or external state.\n- **Both SQLite and PostgreSQL are tested in CI.** Database-related tests run against both.\n\n## Essential Commands\n\n```bash\nuv run pytest tests/                          # Run all tests\nuv run pytest tests/path.py -k test_name      # Run specific test\nuv run pytest tests/module/ -n4               # Run in parallel\nuv run pytest tests/path.py -x                # Stop on first failure\nuv run pytest tests/path.py -x --tb=short     # Compact tracebacks\n```\n\n## Important Fixtures\n\nShared fixtures live in `fixtures/` (see fixtures/AGENTS.md) and root `conftest.py`. The key distinction:\n\n- **Client-side tests** use `prefect_client` (full SDK client). Do not use in server tests.\n- **Server API tests** use `client` / `test_client` (raw httpx/FastAPI against an ephemeral server)\n- **Server model/orchestration tests** use `session` (async SQLAlchemy) and pre-built ORM fixtures (`flow`, `flow_run`, `task_run`, `deployment`, etc.)\n- `test-projects/` — Sample projects used by CLI/deploy tests\n\n## Testing Guidelines\n\n### Database isolation\n\nTests do not get a clean database by default. If a test depends on the DB starting empty — it counts rows, lists \"all X\", or asserts on the absence of records — opt in with `@pytest.mark.clear_db`:\n\n```python\n@pytest.mark.clear_db                # per-test\nasync def test_count_flows(): ...\n\nclass TestFlowAPI:                   # per-class\n    pytestmark = pytest.mark.clear_db\n\npytestmark = pytest.mark.clear_db    # whole module\n```\n\nTests that create resources with UUID-randomized names, filter by IDs they own, or only interact with responses they create themselves usually do not need this marker. Skipping the clear yields a 25–100% suite speedup, so prefer not adding it unless required.\n\nTo check whether a marked file still needs the marker, run it with `--no-clear-db`:\n\n```bash\nuv run pytest tests/path/to/file.py --no-clear-db -x\n```\n\nIf it passes, delete the `pytestmark` (or per-test marker) and commit.\n\n### PREFECT_HOME cleanup\n\n`PREFECT_HOME` is a single temp directory created once per test session (`pytest_sessionstart`), not reset between tests. A test that writes a file directly into it (e.g. a PID file) must delete it in fixture teardown, or later tests in the same session can see it as real state.\n\n### Event assertions\n\nCreating a domain object emits a lifecycle event: building a `flow`, `work_pool`, `variable`, block, concurrency limit, etc. (via fixture or model call) emits `prefect.<object>.{created,...}`. Server tests that assert on `AssertingEventsClient` totals or ordering must `AssertingEventsClient.reset()` after fixture setup, so they count only the events from the action under test rather than the events emitted while building fixtures.\n\n### Type Hints\n- Full type hints on all test functions and fixtures (Python >=3.12 style: `dict[str, str]`)\n- Return type hints on fixtures, omit `-> None` on test functions\n\n### Mocking Strategy\n- Use `unittest.mock` only when necessary (external services, time-sensitive operations)\n- Use `respx` for HTTP response mocking\n\n### Flaky Tests\nWe have a workflow that identifies and fixes tests that flake after merging to main. Check CI test output to see which tests are currently slow or flaky.\n\n**Flow timeout tests**: `pytest-timeout` defaults to SIGALRM on Unix, which interferes with Prefect's own SIGALRM-based flow timeout mechanism. Any test that exercises flow timeouts must opt into thread-based timeouts:\n```python\n@pytest.mark.timeout(method=\"thread\")  # alarm-based pytest-timeout will interfere\nasync def test_flows_fail_with_timeout(self): ...\n```\n\nWhen combining `timeout_seconds` flows with concurrency, use a generous timeout (≥ 2s): the heartbeat-thread setup runs inside the flow's timeout scope and can exhaust a tight timeout before the flow body starts, causing pre-`yield` cancellation on contended CI runners.\n\nUse `retry_asserts` from `prefect._internal.testing` to handle timing-sensitive assertions. Two patterns:\n\n- **Retrying assertions for async event propagation** (most common): wrap the assertion inside `with attempt:` so it retries until the event arrives.\n  ```python\n  async for attempt in retry_asserts(max_attempts=5, delay=0.5):\n      with attempt:\n          callback.assert_called_once_with(flow_run_id)\n  ```\n- **Retrying HTTP requests** (`hosted_api_client` tests): SQLite \"database is locked\" 503 errors can occur due to concurrent access. Retry the HTTP request inside the loop; keep the result assertions *outside* so a wrong result is never masked.\n\n## Related\n\n- `src/prefect/testing/` → Test utilities shipped with the SDK\n- `integration-tests/` → End-to-end tests requiring a running server\n- `ui-v2/e2e/` → Playwright UI tests (see ui-v2/e2e/AGENTS.md)\n",".claude/skills/write-docs/template-howto.mdx":"# Claude Directive: template-howto.mdx\n\nPath: `.claude/skills/write-docs/template-howto.mdx`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/.claude/skills/write-docs/template-howto.mdx)"},"files":{".claude/skills/agents-md-sync/SKILL.md":"---\nname: agents-md-sync\ndescription: Analyze code changes on the current branch and recommend updates to AGENTS.md files that have become stale. Use this skill before creating a PR, when the user asks to check AGENTS.md freshness, or when preparing an AGENTS.md update after a PR merges to main. Trigger whenever the user mentions syncing, updating, or checking AGENTS.md files, or when they're about to create a PR that touches code structure (new modules, renamed directories, changed commands, modified architecture).\n---\n\n# AGENTS.md Sync\n\nDetect when code changes make durable AGENTS.md guidance stale and produce a report with specific recommendations. Treat AGENTS.md files as operating manuals for future agents, not changelogs for recent diffs.\n\n## When to use\n\n- Before creating a PR — check if the branch's changes warrant AGENTS.md updates\n- After a PR merges to main — audit whether merged changes left AGENTS.md files outdated\n- On explicit request — \"are the AGENTS.md files up to date?\"\n\n## Workflow\n\n### 1. Determine the diff\n\nFigure out what changed relative to the base branch. The approach depends on context:\n\n- **On a feature branch (pre-PR):** diff against main\n  ```bash\n  git diff main...HEAD --name-status\n  git diff main...HEAD\n  ```\n- **After a merge to main:** the user should specify which PR or commit range to audit. Use the merge commit or PR number to get the diff:\n  ```bash\n  gh pr diff <number>\n  ```\n- **Explicit check:** if the user just says \"check AGENTS.md\", diff against main\n\n### 2. Map changes to AGENTS.md territories\n\nEach AGENTS.md file \"owns\" the directory it lives in and all subdirectories (unless a child directory has its own AGENTS.md). Build a list of which AGENTS.md files are relevant by walking up from each changed file to find the nearest AGENTS.md.\n\nExample: a change to `src/prefect/server/api/flows.py` is owned by `src/prefect/server/AGENTS.md` (if it exists), otherwise `src/prefect/AGENTS.md`.\n\nOnly analyze AGENTS.md files that have at least one changed file in their territory. Also include parent AGENTS.md files if structural changes (new directories, moved files) affect the directory tree they document.\n\n### 3. Check for missing AGENTS.md files\n\nBefore analyzing existing AGENTS.md files, check whether any changed directories *should* have their own AGENTS.md but don't. New AGENTS.md files should be rare. Recommend one only when the directory has both:\n\n- A real ownership boundary that a future agent needs to recognize before editing\n- Hidden conventions, non-obvious contracts, or recurring pitfalls that cannot be learned quickly from reading the code\n\nLook at the directories containing changed files. For each one that lacks an AGENTS.md, check:\n1. **Ownership boundary**: Does this directory represent a responsibility shift with different contracts than its parent?\n2. **Hidden knowledge**: Are there non-obvious patterns, invariants, conventions, or failure modes that a developer would not learn quickly from code?\n3. **Durability**: Will this guidance still matter after the triggering PR is old news?\n4. **Hierarchy fit**: Would this belong better in an existing parent AGENTS.md instead?\n\nDirectory size and sibling AGENTS.md files can be weak signals, but they are never sufficient on their own. Do not recommend a new AGENTS.md just because a directory has 5+ files, gained a new module, or has sibling directories with AGENTS.md files.\n\nWhen the case is not high-confidence, do not create the file. Capture the possible update as a recommendation instead, with the missing evidence or question that would make it actionable.\n\nWhen recommending a new AGENTS.md, use the Explore agent to read the directory's code and draft the file using this template:\n\n```markdown\n# <Module Name>\n\n<One-sentence purpose statement.>\n\n## Purpose & Scope\n\nWhat this module does. Explicit responsibility boundaries.\nWhat it does NOT do (prevents scope creep).\n\n## Entry Points & Contracts\n\nKey APIs, functions, classes that external consumers use.\nInput/output contracts. Invariants that must hold.\n\n## Usage Patterns\n\nCanonical examples of correct usage.\n\"If you need to do X, here's how.\"\n\n## Anti-Patterns\n\nWhat NOT to do. Common mistakes. Each should be a real mistake, not hypothetical.\n\n## Pitfalls\n\nNon-obvious gotchas. Implicit assumptions.\n\"You'd think X, but actually Y because Z.\"\n```\n\nThe initial content must be concise and durable. Do not include `[ASK]` placeholders, file lists, changelog context, or speculative guidance. If the hidden knowledge cannot be stated confidently, write a recommendation instead of creating the file.\n\n### 4. Analyze each relevant AGENTS.md\n\nAGENTS.md files form a hierarchy — when an agent loads any file, all ancestor files load too, creating a T-shaped view (broad context at the top, specific detail where the agent works). This has two implications for the sync check:\n\n**Least common ancestor rule**: Shared knowledge should live at the shallowest AGENTS.md that covers all paths needing it. If the same fact appears in multiple sibling AGENTS.md files, flag it — it should move to their parent. Conversely, if a parent AGENTS.md contains detail that only applies to one child directory, suggest moving it down.\n\n**Upward propagation**: When a child AGENTS.md changes (or a new one is created), check whether the parent needs updating — either to add a cross-reference to the new child, or to re-summarize what the child directory does. Parent nodes should summarize their children's responsibilities, not duplicate their details.\n\nFor each AGENTS.md in scope, read it fully, then compare its claims against the diff **and** the current source code. Look for these categories of issues:\n\n**Accuracy** — claims in AGENTS.md that don't match the actual code, regardless of whether the diff caused the discrepancy:\n- Described behaviors that don't match what the code actually does (e.g., \"renews at 75% of duration\" when it actually renews immediately then sleeps 75%)\n- Function signatures or parameters listed that are wrong or incomplete\n- Responsibilities attributed to the wrong layer or module\n- Error handling or failure modes described incorrectly\n\nFor claims that are verifiable (specific behaviors, function signatures, which module does what), read the source file and confirm. Don't trust that existing AGENTS.md content was ever correct — it may have been wrong from the start.\n\n**Signal density** — content that duplicates what's discoverable from code rather than surfacing hidden knowledge:\n- Full function signatures that just repeat the code (the *contracts* and *gotchas* around those functions are the high-signal parts)\n- Trivial usage examples that match what's in docstrings or is obvious from the API\n- File-by-file directory listings that `ls` would show — the *layering concept* or *architectural invariant* matters, not the enumeration\n- Content that a developer would learn in 30 seconds of reading the source\n\nAGENTS.md should capture what's *not* visible in the code: invariants, hidden contracts, non-obvious failure modes, things that look one way but behave another.\n\nA behavior discovered in one changed function is not AGENTS-worthy by default.\nPromote it only if it exposes a subsystem-level editing rule, a cross-file\ncontract, or a recurring failure mode future agents need before choosing\nwhich implementation to read. Otherwise prefer a code comment, docstring,\ntest name, or no documentation change.\n\nIf the same guidance is already present in nearby code comments, docstrings, or tests, AGENTS.md should usually not repeat it.\n\n**Missing invariants** — implicit contracts the code relies on that aren't documented:\n- Parallel implementations that must stay in sync (e.g., sync and async versions of the same module)\n- Ordering requirements or sequencing constraints\n- Singleton behaviors or shared mutable state\n- Cleanup responsibilities and what happens when they're skipped\n- \"This looks stateless but actually depends on X\"\n\n**Structural drift** — the AGENTS.md describes an ownership boundary, durable package layout, or module responsibility that no longer matches reality:\n- Directories or packages added/removed/renamed in a way that changes responsibility boundaries\n- New architectural layers or cross-file contracts not mentioned\n- Removed components still listed as active responsibilities\n\n**Command drift** — documented commands that may no longer work or are incomplete:\n- Build/test/run commands referencing changed entry points\n- New tooling or scripts not mentioned\n\n**Convention drift** — code patterns or conventions described in AGENTS.md that the diff contradicts:\n- New patterns established by the changes that aren't documented\n- Existing conventions the changes deprecate or replace\n\n**Description drift** — prose descriptions that no longer accurately characterize the code:\n- Component descriptions that miss new responsibilities\n- Architecture notes that don't reflect refactoring\n\n**Hierarchy drift** — content living at the wrong level in the AGENTS.md tree:\n- Knowledge duplicated across sibling AGENTS.md files that should be in their parent (least common ancestor)\n- Parent-level detail that only applies to one child directory\n- Parent summaries of child directories that no longer match after changes\n\nFor each finding, check whether it's actually stale — read the current state of the filesystem (not just the diff) to confirm. A diff showing a new file, helper, flag, or one-off fix doesn't mean AGENTS.md is wrong if AGENTS.md intentionally omits that level of detail.\n\nOnly recommend or apply updates for high-confidence, lasting guidance:\n- Architectural boundaries\n- Non-obvious invariants\n- Cross-file contracts\n- Recurring failure modes\n- Commands or conventions that future agents are likely to need\n\nDo not document:\n- One-off implementation details or temporary bug context\n- Facts obvious from reading names, imports, or nearby code\n- File lists or every new module\n- Changelog-style summaries of the triggering diff\n- Advice that only matters for the current PR\n\n### 5. Produce the report\n\nOutput a concise report grouped by AGENTS.md file. For each file, list findings with:\n- **What's stale** — the specific line or section\n- **Why** — which change caused it\n- **Suggested fix** — the concrete text to add, remove, or change\n\nFormat:\n\n```markdown\n## AGENTS.md Sync Report\n\n### New AGENTS.md recommended: `src/prefect/utilities/`\n\nThis directory now owns a distinct retry protocol used by multiple callers, and contributors must preserve its ordering invariant. Suggested outline:\n- Purpose and ownership boundary\n- Ordering invariant that callers rely on\n- Failure mode to test when changing it\n\n### `src/prefect/server/AGENTS.md`\n\n1. **[Accuracy]** Lease renewal described as \"renews at 75% of duration\" but code renews immediately then sleeps 75%\n   - Caused by: incorrect from initial creation\n   - Suggested fix: \"renews immediately on entry, then sleeps for 75% of `lease_duration` between renewals\"\n\n2. **[Signal density]** Full function signatures duplicate the code — remove parameter lists, keep contracts\n   - Suggested fix: Replace `concurrency(names, occupy=1, ...)` with `concurrency()` and describe the non-obvious behaviors instead\n\n3. **[Missing invariant]** Sync and async implementations must stay in lockstep but this isn't documented\n   - Suggested fix: Add \"Any behavior change to `_asyncio.py` must be mirrored in `_sync.py`\"\n\n4. **[Structural]** New directory `src/prefect/server/events/` not listed in directory structure\n   - Caused by: `src/prefect/server/events/` added in this branch\n   - Suggested fix: Add `events/` to the directory listing with description\n\n### `./AGENTS.md` (root)\nNo changes needed.\n```\n\nIf nothing is stale, say so clearly — don't manufacture findings.\n\n### 6. Offer next steps\n\nAfter presenting the report, offer:\n- **Apply fixes** — make the suggested edits directly\n- **Create a follow-up PR** — if this is a post-merge audit, offer to create a branch and PR with just the AGENTS.md updates\n- **Skip** — if the changes are minor or the user disagrees with the suggestions\n\n## Reactive mode\n\nOutside of diff-driven analysis, if during normal development you discover missing context that should be in an AGENTS.md, propose an addition. Signs of missing context:\n\n- You spent nontrivial time reconstructing a durable invariant that could be a one-liner in AGENTS.md\n- You hit a non-obvious error because of an undocumented constraint\n- You discovered a cross-system dependency that isn't mentioned anywhere\n- A code review caught something that AGENTS.md should have prevented\n\nPropose additions like this:\n```\nI discovered that [finding]. This isn't in [path]/AGENTS.md.\n\nProposed addition to the [section] section:\n> [concrete text to add]\n\nShould I add this?\n```\n\n## Quality checks for new or updated AGENTS.md content\n\n- **Compression**: Can any section be shorter without losing information?\n- **Deduplication**: Does anything repeat what a parent AGENTS.md already says? If so, remove it and rely on the hierarchy.\n- **Specificity**: Replace vague statements with concrete ones. Not \"be careful with auth\" but \"place logic after the `require_*` call\".\n- **Target length**: 20-80 lines for new files. If longer, compress or write recommendations instead.\n\n## Important guidelines\n\n- Be conservative — only flag things that are genuinely wrong or missing. AGENTS.md files are intentionally concise and don't need to document every file.\n- Don't suggest adding content that's obvious from the code itself. AGENTS.md captures non-obvious patterns, gotchas, and high-level structure. Equally, flag *existing* content that merely restates the code — full function signatures, trivial examples, and file enumerations are low-signal and should be trimmed or replaced with the hidden knowledge around them.\n- Don't trust that existing AGENTS.md content was ever correct. Verify factual claims (behaviors, signatures, responsibility attribution) against the source code, not just against the diff. Content can be wrong from day one.\n- Don't suggest stylistic rewrites. Focus on factual accuracy and signal density.\n- When in doubt about whether something is stale, check the filesystem to confirm rather than guessing from the diff alone.\n- Respect the existing level of detail in each AGENTS.md. If a file only lists top-level directories, don't suggest adding individual files.\n- Look for undocumented invariants — parallel implementations that must stay in sync, ordering constraints, singleton behaviors, cleanup responsibilities. These are the highest-value additions because they're invisible in code and cause the most breakage when violated.\n","client/AGENTS.md":"# prefect-client Package Build\n\nBuild configuration for `prefect-client`, a lightweight subset of `prefect` published as a separate PyPI package. This directory does **not** contain source code — it selects files from `src/prefect/` and repackages them.\n\n## Key Contracts\n\n- **Dependency changes in root `pyproject.toml` that affect client-side code must be mirrored in `client/pyproject.toml`.** This is the most common source of build failures.\n- **New imports in `src/prefect/` can break this build** if they pull in server-only dependencies. The build strips server code, so any import that reaches `server/database`, `server/models`, etc. from client-side code will fail.\n- **The build is tested automatically on every PR** via `.github/workflows/prefect-client.yaml`.\n\n## How It Works\n\n`build_client.sh` copies `src/prefect/` into a temp directory, **deletes** server-only and CLI code, then builds with `client/pyproject.toml`. The resulting package has the same version as `prefect` but fewer dependencies.\n\n### What gets removed\n\n- `cli/` — entire CLI\n- `server/` — database, models, orchestration, schemas, services, utilities (keeps only `server/api/`)\n- `deployments/recipes/` and `deployments/templates/`\n- `testing/`\n\n## Build Triggers\n\n- **PR created** — CI builds and smoke-tests\n- **GitHub release published** — CI builds and publishes to PyPI (same version as `prefect`)\n- **Manual** — `bash client/build_client.sh`\n\nIf the CI build fails, reproduce locally with `bash client/build_client.sh` and run the smoke tests (`client_flow.py`, `client_deploy.py`).\n\n## Related\n\n- `src/prefect/client/` → Actual client SDK source code\n- Root `pyproject.toml` → Must stay in sync with `client/pyproject.toml` for shared dependencies\n",".claude/skills/backlog-management/SKILL.md":"---\nname: backlog-management\ndescription: Manage open-source GitHub issue backlogs (especially PrefectHQ/prefect) in batches. Use for backlog cleanup days, stale review, duplicate pruning, missing-info follow-up, and prioritized queue curation across many open issues.\n---\n\n# Backlog Management\n\nUse this skill for batch backlog work, not for deep triage of a single new issue.\n\n## Scope\n\n- Open-source repositories only.\n- Use public, contributor-friendly language.\n- Do not reference internal plans or private project context.\n\n## Default Mode\n\n- Work in batches of 25-100 issues.\n- Start in read-only mode and propose actions first.\n- Apply edits only after approval unless explicitly asked to execute immediately.\n\n## Workflow\n\n1. Build a candidate batch.\n2. Assign one primary action per issue.\n3. Deep-dive only close candidates.\n4. Draft concise comments where needed.\n5. Apply approved edits.\n6. Report outcomes with counts and issue links.\n\n## Two-Pass Review Depth\n\nUse two passes by default:\n\n- Pass 1 (sweep): classify quickly across the full batch.\n- Pass 2 (dig-in): re-review only `close-not-planned` and `close-duplicate` candidates.\n\nDo not finalize close actions from Pass 1 alone.\n\nFor Pass 2, require explicit evidence:\n\n- architecture/status check against current Prefect behavior\n- concrete links (issue comments, PRs, release notes, docs, code)\n- counterevidence (why issue might still be valid)\n- confidence (`low`, `medium`, `high`)\n\nIf evidence is weak or mixed, downgrade close to:\n\n- `needs:details`\n- `needs:mre`\n- `status:stale`\n- `keep-open`\n\nUI replatform exception:\n\n- Prefect currently has both legacy UI code (`ui/`) and the React replatform (`ui-v2/`).\n- For UI issues that appear tied to legacy UI behavior, do not close based only on age/architecture drift until `ui-v2` is GA.\n- Before proposing close, check whether the reported behavior is represented in `ui/`, `ui-v2/`, or both.\n- Default action before GA is `keep-open` (or `status:stale` only if explicitly desired by maintainers).\n\n## Candidate Queries (PrefectHQ/prefect)\n\nUse focused searches:\n\n```bash\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue no:assignee sort:updated-asc\" --limit 100\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue label:status:stale sort:updated-asc\" --limit 100\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue label:bug -label:needs:mre sort:updated-asc\" --limit 100\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue label:needs:details sort:updated-asc\" --limit 100\n```\n\n## Action Set\n\nChoose exactly one primary action per issue:\n\n- `keep-open`: still actionable, no immediate label change needed\n- `needs:details`: missing context blocks progress\n- `needs:mre`: bug report lacks minimal reproducible example\n- `status:stale`: inactive and low-signal, not exempt\n- `close-duplicate`: close with canonical issue link\n- `close-not-planned`: close with concise reason when clearly out of scope or no longer actionable\n\n## Deep-Dive Output Format\n\nFor every close candidate, produce this mini-record before execution:\n\n- `issue`: number + title\n- `claim_to_verify`: why it appears closable\n- `current_state_check`: does claim still hold today?\n- `evidence_links`: specific references\n- `counterevidence`: any signal to keep open\n- `recommended_action`: final action after deep-dive\n- `confidence`: low/medium/high\n\n## Real Labels (PrefectHQ/prefect)\n\nOnly use labels that exist in this repo. Key labels for backlog work include:\n\n- `needs:details`\n- `needs:mre`\n- `status:stale`\n- `needs:triage`\n- `question`\n- `bug`\n- `enhancement`\n- `good first issue`\n- `blocked`\n- `status:exempt`\n\nVerify labels before applying changes:\n\n```bash\ngh label list --repo PrefectHQ/prefect --limit 30\n```\n\n## Comment Templates\n\nMissing details:\n\n```text\nThanks for opening this. We need a bit more detail before we can move this forward:\n- expected behavior\n- actual behavior\n- exact steps to reproduce\n```\n\nMissing MRE:\n\n```text\nThanks for the report. Please share:\n1) a minimal reproducible code sample,\n2) full traceback/error text,\n3) output of `prefect version`.\n```\n\nDuplicate close:\n\n```text\nClosing as a duplicate of #<issue-number> so discussion stays in one place.\nIf this is materially different, tag me and comment with details; we can reopen.\n```\n\n## Guardrails\n\n- Do not close issues only because they are old.\n- Do not mark as stale when clear maintainer/reporter activity is recent.\n- Do not apply conflicting labels.\n- Do not over-explain; keep comments short and specific.\n- Do not close legacy-UI issues before `ui-v2` GA unless there is a strong non-UI reason (for example, duplicate with active canonical issue).\n","AGENTS.md":"Prefect is a workflow orchestration platform that coordinates and observes data pipelines. It provides a Python SDK for building workflows, a server backend for orchestration, and a web-based UI for managing and monitoring workflows.\n\n# Guiding Principles\n\nYour primary responsibility is to the project and its users. Every change should serve the broader user base — not just the immediate request. Be a quality gate: prefer correct, minimal, well-tested changes over fast ones.\n\n# Before You Start\n\nBefore making code changes, read the public contribution guide in `docs/contribute/dev-contribute.mdx` so your work follows Prefect's contribution expectations, design principles, AI-use policy, testing standards, and maintainer review criteria.\nFor documentation-only changes, also read `docs/contribute/docs-contribute.mdx`.\nFor integration changes, also read `docs/contribute/contribute-integrations.mdx`.\n\n# Directory Structure\n\n```\nprefect/\n├── benches/                         # Benchmarks (CLI, flows, tasks, imports)\n├── client/                          # prefect-client build: subset of src/prefect/ published as a separate PyPI package\n├── compat-tests/                    # Tests for REST API compatibility with Prefect Cloud\n├── Dockerfile                       # Production container image\n├── docs/                            # Mintlify documentation (see docs/AGENTS.md)\n├── examples/                        # Example flows (auto-published to docs)\n├── formal/                          # Executable formal models (see formal/tla/AGENTS.md)\n├── integration-tests/               # End-to-end integration tests (require running server)\n├── justfile                         # Task runner (just <command>)\n├── load_testing/                    # Load/performance testing\n├── plans/                           # Design/implementation plan documents\n├── pyproject.toml                   # Root package config\n├── schemas/                         # JSON schemas (prefect.yaml, settings)\n├── scripts/                         # Code generation and release scripts\n├── src/\n│   ├── integrations/                # External service integrations (see src/integrations/AGENTS.md)\n│   └── prefect/                     # Core package: SDK, server, CLI (see src/prefect/AGENTS.md)\n├── tests/                           # Test suite, mirrors src/prefect/ (see tests/AGENTS.md)\n├── tools/                           # Build tools\n├── ui/                              # Vue UI (legacy, will be replaced by ui-v2)\n├── ui-v2/                           # React UI rewrite (see ui-v2/AGENTS.md)\n└── uv.lock                          # Lockfile (auto-generated, do not edit manually)\n```\n\n# Essential Commands\n\n```bash\n# Dependencies\nuv sync                                # Install all dev dependencies\njust install                           # Same as above, plus perf group\n\n# Running code\nuv run -s my_script.py                             # Run a script with an editable prefect install\nuv run --extra aws repros/1234.py                  # Run repro needing an integration extra\nuv run --project ./src/integrations/<name> <cmd>   # Run against a local integration from repo root\nprefect server start                               # Start local server\nprefect config view                                # Inspect current configuration\n\n# Testing (see tests/AGENTS.md for full details)\nuv run pytest tests/path.py -k name    # Run specific test\nuv run pytest tests/path.py -x -n4     # Parallel, stop on first failure\n\n# Linting & formatting\nuv run ruff check --fix .              # Lint with auto-fix\nuv run ruff format .                   # Format code\nuv run pre-commit run --all-files      # Run all pre-commit hooks\n\n# Docs (from repo root)\njust docs                              # Start Mintlify dev server at localhost:3000\njust generate-docs                     # Regenerate all doc artifacts\n\n# UI (from repo root)\njust ui-v2                             # Start React dev server at localhost:5173\n\n# Docker\ndocker build -t prefect .                              # Default build (Python 3.11)\ndocker build --build-arg PYTHON_VERSION=3.12 -t prefect .  # Custom Python version\ndocker build --build-arg EXTRA_PIP_PACKAGES=\"prefect-aws\" -t prefect .  # With extras\n```\n\n## Quick Reference\n\n| Component | Path | Tests |\n|-----------|------|-------|\n| Core SDK (flows, tasks, states, deployments) | `src/prefect/` | `tests/` |\n| Flow & task engines (async orchestration) | `src/prefect/flow_engine.py`, `task_engine.py` | `tests/engine/` |\n| Client SDK (schemas, HTTP client) | `src/prefect/client/` | `tests/client/` |\n| Server (API, database, scheduling) | `src/prefect/server/` | `tests/server/` |\n| CLI | `src/prefect/cli/` | `tests/cli/` |\n| Settings | `src/prefect/settings/` | `tests/settings/` |\n| Integrations (`prefect-aws`, `prefect-dbt`, etc.) | `src/integrations/` | per-integration |\n| React UI (replacing Vue `ui/`) | `ui-v2/` | `ui-v2/e2e/` |\n\n## Tech Stack & Tooling\n\n- **Python >=3.11,<3.16** with modern typing (`list[int]`, `T | None`)\n- **FastAPI** for REST APIs\n- **Pydantic v2** for validation\n- **SQLAlchemy 2.0** async ORM\n- **Alembic** for database migrations\n- **PostgreSQL/SQLite** databases\n- **React + TypeScript** for UI (see ui-v2/AGENTS.md)\n- **Ruff** for linting and formatting\n- **Pre-commit** hooks: ruff, codespell, mypy (partial), uv-lock, no-commit-to-branch\n\n## Architecture Overview\n\n- **Three user-facing surfaces**: Python SDK (`@flow`/`@task` decorators), CLI (`prefect` command), REST API (FastAPI server)\n- **Server is the source of truth for flow state transitions** — the flow engine proposes states, and the server's orchestration layer accepts or rejects them. Task state transitions are managed locally by the task engine via `set_state` and communicated through `prefect.task_run.*` events\n- **Two published packages**: `prefect` (full SDK + server) and `prefect-client` (lightweight client subset). `client/` contains the build config that selects which files from `src/prefect/` go into `prefect-client`\n- **Integrations are separate PyPI packages** (`prefect-aws`, `prefect-dbt`, etc.) each with their own version, published independently from `src/integrations/`\n- **Async-first execution model** with sync wrappers — the engines (`flow_engine.py`, `task_engine.py`) are async; sync `@flow`/`@task` functions are run in workers\n\n## Anti-patterns\n\n- **Never bypass the server for flow state transitions** — always go through the orchestration API, even in tests. Task state transitions are managed locally by the task engine by design\n- **Never use `pip install` or `uv pip`** — use `uv` for all dependency management\n- **Never use deferred imports** (imports inside functions) unless required to break circular imports or for optional dependencies\n- **Never commit directly to `main`** — a pre-commit hook enforces this\n- **Never skip pre-commit hooks** (`--no-verify`) — fix the underlying issue instead\n- **Never amend commits** (`--amend`) — create new commits instead\n\n# Development Guidelines\n\n## Make sure you have a Prefect server or Prefect Cloud\n- use `prefect config view` to check your current profile\n- run `prefect server start` in the background if needed\n\n## Code Conventions\n\n- Private implementation details (`_private_method`)\n- No public API changes without approval\n- Use single backticks for inline code references in docstrings, not double backticks\n\n## Testing\n\n- Directory structure mirrors source code\n- Run affected tests after changes: `uv run pytest tests/module/`\n- Tests require deterministic behavior\n- Mock external dependencies\n\n## Formal Protocol Models\n\n- Use TLA+ selectively for bounded concurrent or distributed protocols whose correctness depends on interleavings, retries, duplication, time, or ownership. Prefer ordinary tests for local or sequential behavior.\n- Treat each `formal/tla/<protocol>/README.md` as the authority for its scope, configurations, action-to-code mapping, owner, and review triggers.\n- Before changing mapped behavior, review the model and its deterministic regressions. Update them when the abstraction changes; otherwise state in the PR why it remains valid.\n- A green model validates only its documented abstraction, not Prefect's implementation. Implementation evidence comes from mapped behavior and contract tests.\n\n## Working on Issues\n\n- Read the GitHub issue/PR and comments (`gh issue view`, `gh pr view`) before writing code\n- Understand the scope and intended behavior — ask clarifying questions if unclear\n- Create reproduction scripts in `repros/` directory (create it if needed; add to `.gitignore`)\n- Name files by issue number: `repros/1234.py` (only create one file per issue)\n- Ensure the issue is reproducible before fixing\n- Add unit tests for fixes\n- DO NOT delete files from `repros/` directory after reproducing the issue unless asked\n\n## PR Body Style\n\n- Start with \"closes #1234\" if resolving issue\n- Brief summary: \"this PR {changes}\"\n- Details in `<details>` tag\n- Include relevant links\n\n## Code Review Rules\n\nWhen reviewing changes, read and apply [REVIEW.md](REVIEW.md).\n\n# Project Practices\n\n- All PRs require test coverage for new functionality\n- GitHub issues are used for tracking issues (use the `gh` cli)\n- Dependencies: updates to client-side deps in `pyproject.toml` require parallel changes in `client/pyproject.toml`\n- AGENTS.md always symlinked to CLAUDE.md\n",".claude/skills/document-changes/SKILL.md":"---\nname: document-changes\ndescription: Analyze source code changes on the current branch and identify documentation that is stale, inaccurate, or missing. Use before creating a PR to check if docs need updating, or in CI after merges to main to automatically fix docs. Trigger when the user mentions \"doc changes\", \"docs update\", \"check docs\", \"document changes\", or wants to know if code changes affect documentation.\n---\n\n# Document Changes\n\nAnalyze source code changes to find documentation that is stale, inaccurate, or missing, then either report findings or directly apply fixes.\n\n## Modes\n\n- **Report mode (default, local dev):** Produce a structured report of findings with suggested fixes. Offer to apply them.\n- **Edit mode (CI):** Directly apply fixes to existing doc pages. Do not create entirely new pages — flag those as recommendations in the PR body instead.\n\nThe mode is determined by how the skill is invoked. Local interactive use defaults to report mode. CI sets edit mode via the prompt.\n\n## Prerequisites\n\nBefore making any doc edits, read the write-docs skill at `.claude/skills/write-docs/SKILL.md`. All edits must follow its conventions for tone, components, frontmatter, code blocks, and testing directives.\n\n## Workflow\n\n### 1. Determine the diff\n\nFigure out what changed relative to the base branch:\n\n- **On a feature branch (pre-PR):** diff against main\n  ```bash\n  git diff main...HEAD --name-status\n  git diff main...HEAD -- 'src/prefect/' 'src/integrations/'\n  ```\n- **After a merge to main (CI):** read the diff provided at `/tmp/diff.patch`\n- **Explicit check:** diff against main\n\nFilter the diff to only source code changes. Skip:\n- Test files (`**/tests/**`)\n- CI/workflow files (`.github/`)\n- Documentation files (`docs/`, `*.md`, `*.mdx`)\n- Lock files (`uv.lock`, `package-lock.json`)\n- UI files (`ui-v2/`)\n\n### 2. Extract public API surface changes\n\nScan the diff for changes that users would encounter:\n\n**Function and class signatures:**\n- New, renamed, or removed public functions/classes/methods\n- Changed parameters (added, removed, renamed, retyped)\n- Changed default values\n- Changed return types\n\n**CLI commands:**\n- New, renamed, or removed commands (look for `@app.command()`, click/typer decorators)\n- Changed arguments or options\n- Changed help text\n\n**Configuration and settings:**\n- New, renamed, or removed settings (look for `Setting`, `Field` in settings classes)\n- Changed defaults or validation\n- Changed environment variable names\n\n**Behavioral changes:**\n- Changed error types or messages users would see\n- Changed lifecycle behavior (e.g., retry logic, state transitions)\n- Changed defaults that affect runtime behavior\n\n**Skip:**\n- Private/internal symbols (names starting with `_` in `_internal` modules)\n- Type-only changes that don't affect runtime behavior\n- Import reorganizations that don't change the public API\n- Pure refactors with no behavioral change\n\n### 3. Map changes to existing docs\n\nFor each extracted change, search the docs for references. Use parallel searches for efficiency.\n\n**Exclude auto-generated files.** Before searching or editing, filter out all auto-generated doc files. These are maintained by generation scripts and will be updated separately before each release. Never search, flag, or edit these paths:\n- `docs/v3/api-ref/` — entire directory (generated by `scripts/generate_api_ref.py` and `scripts/generate_settings_ref.py`)\n- `docs/v3/examples/` — entire directory (generated by `scripts/generate_example_pages.py`)\n- Any file containing a comment like `This page is generated by` or `automatically generated`\n\n**Search strategy:**\n- Grep `docs/` (excluding auto-generated paths above) for function names, class names, CLI command names, setting names\n- Check concept pages that explain the changed feature's behavior\n- Check how-to guides that demonstrate the changed API\n- Check get-started pages if fundamental APIs changed\n- Check integration docs if integration entry points changed\n\n**Build a findings list with these categories:**\n\n**Stale — docs describe something that changed:**\n- Wrong default value documented\n- Old parameter name or signature\n- Removed feature still documented\n- Behavior description that no longer matches the code\n- Code examples using old API\n\n**Missing — new public API/feature with no doc coverage:**\n- New public function/class with no mention in any doc page\n- New CLI command not documented\n- New setting not listed in configuration docs\n- New feature that extends an existing documented concept\n\n**Broken examples — code blocks that reference changed APIs:**\n- Code blocks using removed or renamed functions\n- Code blocks with old parameter names\n- Code blocks that would produce different output than described\n\n### 4. Produce output\n\n#### Report mode (local dev)\n\nPrint a structured report grouped by doc file:\n\n```markdown\n## Documentation Changes Report\n\n### `docs/v3/concepts/flows.mdx`\n\n1. **[Stale]** Line 45: `@flow(retries=3)` — `retries` parameter renamed to `max_retries` in src/prefect/flows.py\n   - **Suggested fix:** Update parameter name in code example and surrounding prose\n\n2. **[Broken example]** Line 78-85: Code block uses `flow.run()` which was removed\n   - **Suggested fix:** Replace with `flow()` direct invocation\n\n### `docs/v3/how-to-guides/workflows/retries.mdx`\n\n1. **[Stale]** Line 23: \"Default retry delay is 5 seconds\" — default changed to 10 seconds in this branch\n   - **Suggested fix:** Update to \"Default retry delay is 10 seconds\"\n\n### Missing coverage\n\n1. **[Missing]** New `@flow(on_cancellation=...)` hook added — no docs mention this parameter\n   - **Recommendation:** Add a section to `docs/v3/concepts/flows.mdx` under \"Flow lifecycle hooks\" or create a new how-to guide\n\n### No changes needed\n- `docs/v3/get-started/quickstart.mdx` — references checked, all current\n```\n\nAfter presenting the report, offer:\n- **Apply fixes** — make the suggested edits to existing pages (follow write-docs skill conventions)\n- **Skip** — if the user disagrees with findings or wants to handle manually\n\n#### Edit mode (CI)\n\nDirectly apply fixes for **Stale** and **Broken example** findings on existing pages:\n- Skip any file under an auto-generated path (`docs/v3/api-ref/`, `docs/v3/examples/`) or containing a generated-by comment — do not edit these even if they appear stale\n- Read each affected doc file\n- Make targeted, minimal edits to fix the specific issues\n- Do not rewrite surrounding content\n- Do not change tone, style, or structure beyond what's needed\n- For code blocks, ensure the fix is syntactically valid\n- Add `{/* pmd-metadata: notest */}` only if the fixed code genuinely can't be tested\n\nFor **Missing** coverage findings, do not create new pages. Instead, collect them for the PR body.\n\n### 5. Quality gate (edit mode only)\n\nBefore considering edits complete, verify each change:\n- Follows write-docs tone (second person, active voice, no marketing language)\n- Uses Mintlify components correctly (not markdown admonitions)\n- Preserves existing frontmatter (title, description, keywords)\n- Does not add or remove pages from `docs/docs.json`\n- Code blocks are syntactically valid Python/bash\n- Changes are minimal — only what's needed to fix the finding\n\n### 6. Offer next steps (report mode only)\n\nAfter applying fixes (if the user chose to), mention:\n- Run `just lint` in `docs/` to check Vale style\n- Run markdown tests if code blocks were modified\n- Any missing coverage items that need new content written (suggest using the write-docs skill)\n\n## Important guidelines\n\n- **Be conservative.** Only flag things that are genuinely wrong or missing. A doc page that doesn't mention every parameter is fine — it's stale only if it mentions the *wrong* value or a *removed* thing.\n- **Don't rewrite for style.** If the prose is accurate, leave it alone even if you'd write it differently.\n- **Verify before flagging.** Read both the diff and the current doc file. A grep hit doesn't mean the doc is wrong — read the context.\n- **Respect doc scope.** Not every public API needs docs. Flag missing coverage for features users would reasonably expect to find documented, not for every internal helper that happens to be public.\n- **Minimize blast radius in CI.** Small, targeted fixes only. If a finding requires judgment about page structure or new content, leave it as a recommendation rather than an automated edit.\n- **Don't touch auto-generated pages.** Skip the entire `docs/v3/api-ref/` directory (including `settings-ref.mdx`, Python SDK reference, CLI reference, and REST API reference), the entire `docs/v3/examples/` directory, and any file containing a generated-by comment (e.g., `This page is generated by`). These files are regenerated by scripts before each release and must not be edited manually or by automation.\n- **Check code block test directives.** If you modify a code block, check whether it has `pmd-metadata` directives and preserve them. If you're unsure whether a modified block is testable, mark it `notest` and note why.\n",".claude/skills/write-docs/SKILL.md":"---\nname: write-docs\ndescription: Comprehensive guide for writing and updating Prefect documentation. Use when creating new doc pages, updating existing docs, or working with Mintlify components and code example testing.\n---\n\n# Writing Prefect Documentation\n\nThis guide covers everything needed to write, update, and test Prefect documentation pages. For structural context (directory layout, navigation, links, local dev commands), see `docs/AGENTS.md`.\n\n## Page types\n\nEach section of the docs serves a distinct purpose. Place new content in the right section and match its tone and structure.\n\n### Get Started (`v3/get-started/`)\n\nOnboarding pages for new users. Content should be linear, opinionated, and get the reader to a working result as fast as possible. Use `<Steps>` for sequential instructions and `<Tabs>` to offer Cloud vs. self-hosted paths. Minimize explanation — link to Concepts for deeper understanding.\n\n### Concepts (`v3/concepts/`)\n\nExplain **what** something is and **why** it matters. Concepts pages define Prefect's mental model — flows, tasks, states, deployments, events, work pools, etc. Start with a short code example showing the concept in action, then explain the underlying model, lifecycle, and relationships to other concepts. Link to How-to Guides for step-by-step instructions. Do not provide exhaustive procedural walkthroughs here.\n\n### How-to Guides (`v3/how-to-guides/`)\n\nTask-oriented pages that show **how** to accomplish a specific goal. Each page should solve one problem (e.g., \"How to write and run a workflow\", \"How to set up retries\"). Structure as a series of actionable steps with code examples. Meet the reader where they are — do not assume familiarity with Prefect internals. Use the smallest amount of Prefect-specific jargon possible, and explain or link terms when they are unavoidable.\n\nGuides are organized into the following categories:\n\n- **`workflows/`** — Writing, running, and customizing flows and tasks: retries, caching, concurrency, logging, testing, runtime info, state hooks, and artifacts.\n- **`deployments/`** — Creating, scheduling, running, and versioning deployments, including `prefect.yaml` configuration and flow code storage.\n- **`deployment_infra/`** — Running workflows on specific infrastructure: Docker, Kubernetes, serverless platforms (AWS ECS, Azure ACI, GCP Cloud Run), Modal, Coiled, Prefect Managed, and local processes. Also covers work pool management.\n- **`automations/`** — Setting up event-driven automations: creating automations and triggers, chaining deployments via events, custom notifications, and accessing event payloads in flows.\n- **`cloud/`** — Prefect Cloud-specific operations: connecting to Cloud, managing workspaces and users, creating webhooks, and troubleshooting.\n- **`configuration/`** — Configuring the Prefect environment: managing settings, storing secrets, and using variables.\n- **`ai/`** — Using Prefect with AI tooling, such as the Prefect MCP server.\n- **`migrate/`** — Upgrading from older Prefect versions or migrating from other tools like Airflow.\n- **`self-hosted/`** — Running the Prefect server yourself via Docker Compose, the CLI, or on Windows.\n\n### Advanced (`v3/advanced/`)\n\nIn-depth pages for experienced users covering topics like transactions, interactive workflows, infrastructure-as-code, scaling self-hosted deployments, and custom API integrations. These assume familiarity with core concepts and how-to patterns. They can be longer and more detailed than how-to guides.\n\n### Examples (`v3/examples/`)\n\n**Auto-generated — do not edit directly.** Each page is generated from a standalone Python file in the repo's top-level `examples/` directory by `generate_example_pages.py`. To add an example, create a new `.py` file in `examples/` with YAML frontmatter in comments and run `just generate-examples`. See `contribute/docs-contribute.mdx` for the full process.\n\n### Integrations (`integrations/`)\n\nEach integration (e.g., `prefect-aws`, `prefect-gcp`) has its own subdirectory. The `index.mdx` covers installation, credential setup (blocks), and key capabilities. Additional pages cover specific workers, tasks, or SDK reference. Follow the existing pattern: \"Why use it\" section, prerequisites, install instructions, blocks setup, then per-service usage sections.\n\n### API Reference (`v3/api-ref/`)\n\n**Auto-generated — do not edit directly.** Covers the Python SDK (`python/`), CLI commands (`cli/`), and REST API (`rest-api/`). CLI pages use `<ResponseField>` and `<Accordion>` components for arguments and options.\n\n### Release Notes (`v3/release-notes/`)\n\nChangelogs organized by product surface: `oss/` for open-source releases, `cloud/` for Prefect Cloud, `integrations/` for integration packages.\n\n### Contribute (`contribute/`)\n\nGuides for contributors: how to set up the dev environment, write docs, develop integrations, and follow code style conventions.\n\n## Adding vs. updating content\n\n### When to update an existing page vs. create a new one\n\n- **Update an existing page** when the new content is a variation, option, or closely related technique for something the page already covers. For example, a new retry strategy belongs on the existing retries page, not a new page.\n- **Create a new page** when the content addresses a distinct goal that doesn't fit naturally into any existing page. A good test: if the page title would need to become vague or a compound sentence to accommodate the new content, it deserves its own page.\n- When in doubt, prefer extending an existing page. Fewer, more comprehensive pages are easier for readers to discover than many small, fragmented ones.\n\n### When to add a new category or section\n\n- **Create a new subdirectory** only when you have multiple pages (or a clear roadmap for multiple pages) that share a theme not covered by any existing category. A single page does not justify a new category — place it in the closest existing one.\n- Before creating a category, check whether the content fits in an existing one. For example, a guide about running flows on a new cloud platform belongs in `deployment_infra/`, not a new category named after that platform.\n- New categories must also be added as a group in the `navigation.tabs` section of `docs/docs.json`, with an `index.mdx` page for the group overview.\n\n## Page templates\n\nStarter templates live in this skill directory. Copy one as the basis for a new page and fill in the bracketed placeholders:\n\n- **How-to guide** — `template-howto.mdx`\n- **Concept page** — `template-concept.mdx`\n\nAdjust headings and sections to fit the content — the templates show the expected shape, not a rigid format.\n\n### Keywords for searchability\n\nEvery page should include a `keywords` array in its frontmatter. Keywords feed Mintlify's search index and help readers find pages using terms that don't appear in the title or description.\n\n```yaml\nkeywords: [\"retry\", \"retries\", \"error handling\", \"fault tolerance\"]\n```\n\n- Include 3-5 lowercase terms a reader might search for.\n- Use synonyms and shorthand readers would actually type (e.g., \"k8s\" is wrong in prose but useful as a keyword alongside \"Kubernetes\").\n- Don't repeat words already in `title` or `description` — those are indexed automatically.\n\n## Registering pages in navigation\n\nEvery new page must be added to `docs/docs.json` under `navigation.tabs` or it won't appear in the sidebar. Add the page path (without `.mdx`) to the appropriate group:\n\n```json\n{\n  \"tab\": \"How-to Guides\",\n  \"pages\": [\n    \"v3/how-to-guides/index\",\n    {\n      \"group\": \"Workflows\",\n      \"pages\": [\n        \"v3/how-to-guides/workflows/write-and-run\",\n        \"v3/how-to-guides/workflows/retries\"\n      ]\n    }\n  ]\n}\n```\n\n- Each tab has a `\"tab\"` display name and either `\"pages\"` or `\"groups\"`.\n- Groups can nest: a group's `\"pages\"` array can contain strings (page paths) or nested `{\"group\": ..., \"pages\": [...]}` objects.\n- Place new pages at a logical position within the existing group — typically at the end, unless ordering matters for the reader.\n\n## Mintlify components\n\nUse these components (not standard Markdown admonition syntax):\n\n```mdx\n<Note>Important information.</Note>\n<Warning>Caution about potential issues.</Warning>\n<Tip>Helpful suggestion.</Tip>\n<Info>Additional context.</Info>\n\n<Accordion title=\"Expandable section\">\n  Content hidden until clicked.\n</Accordion>\n\n<Tabs>\n  <Tab title=\"Option A\">Content for A</Tab>\n  <Tab title=\"Option B\">Content for B</Tab>\n</Tabs>\n\n<Steps>\n  <Step title=\"First step\">Instructions</Step>\n  <Step title=\"Second step\">Instructions</Step>\n</Steps>\n\n<CardGroup cols={3}>\n  <Card title=\"Title\" icon=\"icon\" href=\"/v3/path\">\n    Description text.\n  </Card>\n</CardGroup>\n\n<CodeGroup>\n```bash pip\npip install prefect\n```\n```bash uv\nuv pip install prefect\n```\n</CodeGroup>\n```\n\n## Reusable snippets\n\nSnippets live in `snippets/` and are imported with JSX:\n\n```mdx\nimport ComponentName from '/snippets/path.mdx'\n\n<ComponentName />\n```\n\nAlways check for an existing snippet before writing duplicate content. Key snippets to know about:\n\n- `snippets/installation.mdx` — Standard Prefect install instructions (used in `v3/get-started/install.mdx`). Use this instead of writing ad-hoc install blocks.\n- `snippets/resource-management/` — Consistent \"manage this resource via CLI / API / Terraform / Helm\" callouts. Import the relevant variant when documenting a Prefect resource.\n\n## Code blocks\n\nCode blocks support language hints, filenames, line highlighting, and expandable sections:\n\n````mdx\n```python my_flow.py\nfrom prefect import flow\n\n@flow\ndef hello():\n    print(\"Hello!\")\n```\n\n```bash {3} [expandable]\nprefect deploy --all\nprefect work-pool create my-pool --type process\nprefect worker start --pool my-pool\n```\n````\n\nMark code blocks that should **not** be tested with the comment `{/* pmd-metadata: notest */}` on the line before the code block.\n\nPrefer minimal, runnable snippets that produce a visible result (printed output, a return value, or a logged message). Avoid placeholder names like `foo`/`bar` in user-facing examples — use realistic names that reflect the domain (e.g., `process_order`, `customer_id`).\n\n## Code example testing\n\nPython code blocks in `.mdx` files are automatically extracted and executed as tests using [pytest-markdown-docs](https://github.com/modal-labs/pytest-markdown-docs). Tests run in CI against a live Prefect server and are parallelized with pytest-xdist (up to 6 workers). All test configuration — fixtures, skip lists, and injected globals — lives in `docs/conftest.py`.\n\n### How it works\n\nBy default, every fenced Python code block in an `.mdx` file is treated as an independent test. The plugin extracts the block, executes it, and fails if it raises an exception. Each block runs in its own namespace unless `continuation` is used (see below).\n\n### Running tests locally\n\nThere is no `just` command for markdown tests. Run them manually:\n\n```bash\n# Start a Prefect server in the background\nPREFECT_HOME=$(pwd) uv run prefect server start &\n\n# Run the markdown doc tests\nPREFECT_API_URL=\"http://127.0.0.1:4200/api\" uv run --group markdown-docs pytest docs/ -m markdown-docs\n```\n\n### pmd-metadata directives\n\nControl test behavior with `{/* pmd-metadata: <directive> */}` comments placed on the line immediately before a code fence.\n\n**`notest`** — Skip this code block entirely. Use when code is illustrative, incomplete, or requires setup that cannot be provided in the test environment.\n\n```mdx\n{/* pmd-metadata: notest */}\n```python\n# This block will not be tested\nprefect deploy --some-hypothetical-flag\n```\n```\n\n**`continuation`** — Share state (imports, variables, function definitions) from preceding code blocks on the same page. Without this, each block starts with a clean namespace. Use when a multi-step example is split across blocks for readability.\n\n```mdx\n```python\nfrom prefect import flow\n\n@flow\ndef my_workflow() -> str:\n    return \"Hello, world!\"\n```\n\n{/* pmd-metadata: continuation */}\n```python\nmy_workflow()  # Can reference the function defined above\n```\n```\n\n**`fixture:<name>`** — Inject a pytest fixture defined in `conftest.py` as a global in the code block. Use when a block needs mocking (e.g., HTTP calls).\n\n```mdx\n{/* pmd-metadata: fixture:mock_post_200 */}\n```python\nimport requests\nresponse = requests.post(endpoint, headers=headers, json=data)\nassert response.status_code == 200\n```\n```\n\n### Global imports\n\nThe `pytest_markdown_docs_globals` hook in `conftest.py` injects a small set of globals into every code block automatically: `Mapped`, `Run`, `Union`, `mapped_column`, `sa`. You do not need to import these in doc examples.\n\n### Autouse fixtures\n\nTwo fixtures are applied to every test automatically (defined in `conftest.py`):\n\n- `mock_runner_start` — Mocks `prefect.cli.flow.Runner.start` so flow-serving examples don't actually start a long-running process.\n- `mock_base_worker_submit` — Mocks `BaseWorker.submit` and `KubernetesWorker.submit` so worker examples don't attempt real infrastructure calls.\n\n### Skipped files\n\nSome files are skipped entirely via the `SKIP_FILES` dict in `conftest.py`. Common reasons include needing database fixtures, block cleanup, live network calls, or async contexts. Additionally:\n\n- All files under `v3/api-ref/python/` are auto-skipped (generated reference docs).\n- All files under `v3/examples/` are auto-skipped (tested separately in their source repo).\n\nWhen adding a new page that genuinely cannot be tested, add it to `SKIP_FILES` with a reason rather than marking every block with `notest`.\n\n## Images\n\nPlace images in `v3/img/` organized by section (e.g., `v3/img/ui/`, `v3/img/concepts/`). Reference them with absolute paths:\n\n```mdx\n![Description](/v3/img/ui/screenshot.png)\n```\n\n- Always include meaningful alt text that describes what the image shows.\n- Use compressed PNG or WebP format to keep page load times fast.\n- Avoid committing unnecessarily large screenshots; crop to the relevant area.\n\n## Linting\n\nDocs are linted with [Vale](https://vale.sh/) using Google style, Vale defaults, and custom Prefect rules. Run locally:\n\n```bash\njust lint\n```\n\nOr manually: `vale --glob='**/*.{md,mdx}' .`\n\n## Tone and style\n\n- Use second person (\"you\") and active voice in present tense.\n- Avoid first person (\"I\", \"we\") and marketing language (\"powerful\", \"seamless\", \"best-in-class\").\n- Be direct and concise. Shorter sentences are easier to scan.\n- Follow the [Google developer documentation style guide](https://developers.google.com/style) as the baseline.\n\nExamples of preferred phrasing:\n\n| Instead of | Write |\n|---|---|\n| \"We recommend configuring...\" | \"Configure...\" |\n| \"You'll want to make sure to...\" | \"Make sure to...\" or just state the instruction |\n| \"This powerful feature allows you to...\" | \"Use [feature] to...\" |\n| \"I'll show you how to set up...\" | \"To set up..., do the following:\" |\n| \"It should be noted that...\" | State the fact directly |\n| \"In order to\" | \"To\" |\n\nWhen introducing a concept, lead with what the reader can *do*, not what the feature *is*:\n\n- Before: \"The retry mechanism is a configurable system that allows flows to recover from transient failures.\"\n- After: \"Add retries to your flow to recover automatically from transient failures.\"\n\n## Quality checklist\n\nBefore considering a page complete, verify:\n\n1. The page opens with appropriate context: for how-to guides, a single-sentence scope line (or jump straight into steps if the title already establishes the goal); for concepts and advanced pages, an opening paragraph that defines the topic and why it matters.\n2. Prerequisites (tools, access, prior knowledge) are called out up front.\n3. The page includes at least one cross-link to a related Concept or How-to page.\n4. All code blocks are runnable and tested, or explicitly marked with `{/* pmd-metadata: notest */}` with a reason.\n5. Frontmatter includes `keywords` with 3-5 search terms not already in the title or description.\n6. The page is registered in `docs/docs.json` navigation.\n\n## Common mistakes\n\n- Using `#` (H1) in the body — the frontmatter `title` already renders as H1.\n- Using relative links or including `.mdx` in link paths.\n- Using Markdown admonitions (`> **Note:**`) instead of Mintlify components (`<Note>`).\n- Inconsistent heading hierarchy (jumping from H2 to H4).\n- Missing `description` or `keywords` in frontmatter — both improve search discoverability.\n- First-person pronouns (\"I\", \"we\") — use \"you\" or imperative voice.\n- Wrong terminology casing: \"Prefect cloud\" (should be \"Prefect Cloud\"), \"Prefect Server\" (should be \"Prefect server\"), \"k8s\" (should be \"Kubernetes\"), \"infra\" (should be \"infrastructure\").\n- Forgetting to register a new page in `docs/docs.json` — the page won't appear in nav.\n- Forgetting to add a redirect in `docs/docs.json` when moving or renaming a page.\n- Overusing `<Note>`/`<Tip>`/`<Warning>` — reserve for genuinely important callouts, not every paragraph.\n","integration-tests/AGENTS.md":"# Integration Tests\n\nEnd-to-end tests that require a live Prefect server and verify the full orchestration pipeline across process boundaries.\n\n## Purpose & Scope\n\nThese tests cover scenarios that unit tests cannot: real server ↔ worker communication, subprocess flow execution, cancellation across process boundaries, event delivery, and scheduling statefulness.\n\nThey do NOT duplicate unit tests in `tests/`. If a behavior can be tested in isolation, it belongs there.\n\n## Running\n\n```bash\n# Integration tests are excluded from the default testpaths in pyproject.toml — they will NOT run with uv run pytest tests/\nuv run pytest integration-tests/\nuv run pytest integration-tests/test_nested_cancellation.py\n```\n\nRequirements:\n- `PREFECT_API_URL` must point to a running Prefect server (check with `prefect config view`)\n- `uv` must be available in `PATH`\n\nSome tests accept additional env vars: `SERVER_VERSION` (skip version-specific tests), `PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE`, `PREFECT_API_AUTH_STRING`.\n\n## Structure\n\nNo shared `conftest.py`. Each test file is self-contained with its own helpers and fixtures inline. There are no pytest fixtures shared across files.\n\n## Usage Patterns\n\n**Poll, don't assert synchronously.** Hook execution, state transitions, and marker-file writes are independent side effects of the same cancel/complete sequence — the API state can become visible before the hook's file is written. Use `_wait_for()` instead of a bare `assert`:\n\n```python\n# Wrong — races on rare timing:\nassert Path(marker_dir, HOOK_MARKER).exists()\n\n# Right — polls until satisfied or timeout:\n_wait_for(\n    lambda: Path(marker_dir, HOOK_MARKER).exists(),\n    timeout=30,\n    message=\"Hook did not write its marker.\\n\" + _worker_output(log_path),\n)\n```\n\n**Marker files for cross-process state.** Flows running in subprocesses write files to a shared `tmp_path` to signal that a state was reached. Name markers with constants (`PARENT_HOOK_MARKER`, `CHILD_STARTED_MARKER`, etc.) and document them at the top of the file.\n\n**Subprocess invocations use `uv --isolated`.** All CLI calls go through `uv.find_uv_bin()` with `--isolated` to get a clean environment:\n\n```python\nsubprocess.run([uv.find_uv_bin(), \"run\", \"--isolated\", \"prefect\", \"worker\", \"start\", ...])\n```\n\n`PREFECT_API_URL` is inherited from the calling process's env — it still needs to be set.\n\n**Unique work pool names.** Always suffix with `uuid4()` to avoid conflicts across parallel test runs.\n\n**Explicit cleanup in `finally`.** Deployments, work pools, and subprocesses must be cleaned up manually — there is no pytest fixture teardown:\n\n```python\ntry:\n    # set up pool, deployment, worker, run assertions\nfinally:\n    client.delete_work_pool(pool_name)\n    proc.terminate()\n    try:\n        proc.wait(timeout=5)\n    except subprocess.TimeoutExpired:\n        proc.kill()\n```\n\n## Anti-Patterns\n\n- Don't assert synchronously on hook markers or other side effects right after triggering a cancellation — always poll.\n- Don't use fixed `asyncio.sleep()` delays as a substitute for `_wait_for()` — they either waste time or still race.\n- Don't share state between test files via module-level globals — each file is standalone.\n- Don't use subprocess CLI for infrastructure setup/teardown (work pool CRUD, deployment creation) — use `get_client(sync_client=True)` API calls instead. Subprocess is only for testing cross-process behavior (starting workers, executing flow runs in a separate process).\n\n## Pitfalls\n\n- `PREFECT_API_URL` not set produces cryptic errors, not a helpful configuration message. Check it first.\n- These tests are slow (seconds to minutes per test) and intentionally excluded from the default `testpaths` in `pyproject.toml`.\n- Process `terminate()` sends SIGTERM but the subprocess may not exit immediately — always `wait(timeout=...)` and fall back to `kill()`.\n- WebSocket event subscriptions are not active until the `async with get_events_subscriber(...)` context establishes the server connection — events emitted before that happens are silently lost. Signal readiness from *inside* the subscription context using a `threading.Event`, and `assert ready.wait(timeout=30)` before triggering any events in the test.\n","docs/AGENTS.md":"# Prefect Documentation\n\nStructural context for any agent working in `docs/`. For the full writing guide (page types, components, code testing, style), use the `/write-docs` skill.\n\n## Platform\n\n[Mintlify](https://mintlify.com/) docs published to [docs.prefect.io](https://docs.prefect.io). All files use `.mdx` (Markdown + JSX). Site config lives in `docs/docs.json`.\n\n## Directory structure\n\n```\ndocs/\n  v3/                     # Primary docs for Prefect 3.x\n    get-started/          # Installation, quickstart\n    concepts/             # Core concepts (flows, tasks, states, deployments, etc.)\n    how-to-guides/        # Practical guides organized by category\n    advanced/             # Advanced topics\n    examples/             # Auto-generated from examples/ Python files — do NOT edit directly\n    api-ref/              # API reference — mix of auto-generated and hand-authored\n      python/             # SDK reference (auto-generated — do NOT edit directly)\n      cli/                # CLI command reference (auto-generated — do NOT edit directly)\n      rest-api/           # REST API docs (server/ and cloud/) — endpoint pages auto-generated; index.mdx overview pages are hand-authored\n      events/             # Events reference catalog — hand-authored, editable\n    release-notes/        # Version release notes\n    img/                  # Images organized by section\n  integrations/           # Integration-specific docs (prefect-aws, prefect-gcp, etc.)\n  contribute/             # Contributor guides\n  snippets/               # Reusable MDX snippets imported across pages\n  images/                 # Legacy images\n  logos/                  # Brand assets\n  styles/                 # Vale linting styles\n  resources/              # Unlisted pages (hidden: true) outside the v3/ versioning tree\n```\n\n## Auto-generated content — do not edit\n\n- `v3/examples/` — generated from top-level `examples/` Python files by `generate_example_pages.py`\n- `v3/api-ref/python/`, `v3/api-ref/cli/` — generated API reference (Python SDK, CLI)\n- `v3/api-ref/rest-api/` — individual endpoint pages are auto-generated; the `index.mdx` files at `rest-api/` and `rest-api/server/` are hand-authored and may be edited\n- `v3/api-ref/events/` is **hand-authored** and should be edited directly when event schemas change\n- `integrations/<name>/api-ref/` — generated per-integration API reference via `mdxify` (e.g., `integrations/prefect-kubernetes/api-ref/`); regenerated on each integration release\n\n## File format\n\nEvery `.mdx` file starts with YAML frontmatter:\n\n```yaml\n---\ntitle: Page Title\ndescription: Brief description for SEO and navigation\nsidebarTitle: Optional shorter sidebar label   # optional\nicon: icon-name                                # optional, Mintlify icon\nmode: wide                                     # optional; use \"custom\" for raw JSX/HTML layouts\nhidden: true                                   # optional; unlisted page — no nav registration needed\nkeywords: [\"keyword1\", \"keyword2\"]             # optional, for search\n---\n```\n\nFrontmatter keys are always lowercase. The `title` renders as the page's H1, so start body content at `##` — do not add another H1.\n\n## Navigation\n\nAll pages must be registered in `docs/docs.json` under `navigation.tabs`. When adding a page, add its path (without `.mdx` extension) to the appropriate group.\n\n## Links\n\nUse absolute paths from the docs root without `.mdx`:\n\n```mdx\nSee the [flows documentation](/v3/concepts/flows) for details.\n```\n\nDo not use relative paths or include `.mdx` in links.\n\n## Redirects\n\nWhen renaming or moving a page, add a redirect in `docs/docs.json` `redirects` array so existing links continue to work. Never remove existing redirects unless you are certain the old URL has no inbound traffic. Paths should not include `.mdx`.\n\n## Terminology and casing\n\nPreferred terms are enforced by Vale via `docs/styles/CustomStyles/WordList.yml`. Key entries:\n\n- \"Prefect Cloud\" (not \"Prefect cloud\")\n- \"Prefect server\" (not \"Prefect Server\")\n- \"infrastructure\" (not \"infra\")\n- \"Kubernetes\" (not \"k8s\")\n- \"open source\" (not \"open-source\")\n\n## Versioning\n\nAll new content goes in `docs/v3/`. Do not create pages outside `v3/` for current Prefect 3.x features. Exception: unlisted pages (`hidden: true`) can live in `docs/resources/`.\n\n## Local development\n\n```bash\njust docs     # Start the dev server at localhost:3000\njust links    # Check for broken links\njust lint     # Run Vale linter\n```\n\n## Key rules\n\n1. **Do not edit auto-generated files.** Pages under `v3/examples/`, `v3/api-ref/python/`, `v3/api-ref/cli/`, `v3/api-ref/rest-api/`, and `integrations/<name>/api-ref/` are generated from source code. The exception is `v3/api-ref/events/`, which is hand-authored and should be edited when event schemas change.\n2. **Register new pages in `docs/docs.json`.** An unregistered page won't appear in navigation. Exception: pages with `hidden: true` are unlisted and do not require navigation registration.\n3. **Use `.mdx` extension** for all new documentation files.\n4. **Use Mintlify components** (`<Note>`, `<Tabs>`, `<Steps>`, etc.) rather than Markdown-native admonition syntax.\n5. **Keep code examples working.** They are tested in CI via `pytest-markdown-docs`. Two skip mechanisms exist:\n   - Per-block: add `{/* pmd-metadata: notest */}` above the fenced code block when a single example can't run in isolation.\n   - Per-file: add the path to `SKIP_FILES` in `docs/conftest.py` when an entire page requires real external infrastructure (a live database, a dbt project and profiles, real API credentials). Integration pages almost always fall into this category.\n6. **Use absolute link paths** without file extensions (e.g., `/v3/concepts/flows`).\n7. **Check for existing snippets** in `snippets/` before duplicating content.\n8. **Start body content at `##`.** The frontmatter `title` renders as H1; do not add another H1 in the body.\n9. **Document and mark Cloud-only features.** Some features are only available in Prefect Cloud and have no open source equivalent (SSO, audit logs, incidents, SLAs, the `send-email-notification` automation action, etc.). These originate in the `nebula` repo, so they are documented by Prefect staff and agents rather than external contributors. Make sure they are documented here and marked so customers and downstream consumers (such as the Terraform provider and SDKs) can discover them. Conventions:\n   - **Where Cloud-only guides live.** Account, workspace, and user management guides live under `v3/how-to-guides/cloud/`. Prefer this location for new Cloud-only how-to content.\n   - **Mark the feature** when it appears on a page that also covers open source behavior (for example a shared concept page), so readers can tell the editions apart. Use one of:\n     - A Cloud badge on its own line, directly above the page or section it marks: `<span class=\"badge cloud\"></span>`. It renders a standalone \"Prefect Cloud\" label and the span is intentionally empty; put a blank line before the following prose so it scopes the whole section rather than a single sentence.\n     - A `<Note>This action is only available in Prefect Cloud.</Note>` callout for inline cases (e.g. a single table row or variable).",".claude/commands/repro.md":"---\ndescription: Reproduce a bug in the Prefect codebase.\nargument-hint: \"[the gh issue link or issue number]\"\n---\n\nuse `gh` to read and understand the following github issue: $1.\n\nRead the body and all comments in the issue.\n\nbefore reproducing, `rg` for documentation in `docs/` that may be relevant to the issue.\n\nif a `repros/` directory already exists (it will be locally gitignored), `rg` for relevant SDK usage to gain context.\n\n\nTo reproduce, create a file named by issue number (ie. `1234.py`) in a locally gitignored (.git/info/exclude) `repros/` directory with a minimal reproducible example that reproduces the issue. Because `repros/` is gitignored, you should NEVER reference it in a PR body, instead put the entire reproduction script in a python snippet inside a `<details>` tag.\n\nIf the reproduction requires external dependencies, use `uv` to inline script dependencies to install them like this:\n\n```\n# ///script\n# dependencies = [\"pandas\", \"numpy\"]\n# ///\n\n# rest of script\n```\nand then invoke the script with `uv run --with-editable . repros/1234.py` to use the editable copy of Prefect along with the external dependencies.\n\nReview the actual `prefect` library in `src/prefect` (or integration in `src/integrations`) to ensure that the reproduction is aware of the implementation details of the code.\n",".claude/skills/write-docs/template-concept.mdx":"---\ntitle: [Concept name]\ndescription: [One sentence explaining what this concept does.]\nkeywords: [\"keyword1\", \"keyword2\", \"keyword3\"]\n---\n\n{/*\n  keywords: Include 3-5 lowercase terms a reader might search for.\n  Use synonyms and abbreviations readers would type — e.g., for a\n  flows page: [\"flow\", \"workflow\", \"orchestration\", \"decorator\"].\n  Don't repeat words already in the title or description.\n*/}\n\n```python\nfrom prefect import flow\n\n@flow\ndef my_flow():\n    return \"Hello!\"\n\nmy_flow()\n```\n\n## What is [concept]?\n\nExplain the concept and why it matters.\n\n## [Key aspect or behavior]\n\nDeeper explanation with examples.\n\n<Tip>\nCall out a key detail the reader should remember.\n</Tip>\n\n## Next steps\n\n- [How to do X with this concept](/v3/how-to-guides/category/guide)\n","ui-v2/AGENTS.md":"# Prefect UI v2 - React Migration\n\nThis is the new React-based Prefect UI, migrating from the legacy Vue application with minimal visual and functional changes.\n\n## Project Structure\n\n```\nprefect/ui-v2/\n├── src/\n│   ├── api/           # API queries, mutations, and mocks\n│   ├── auth/          # Authentication state, AuthProvider, useAuth hook\n│   ├── components/    # React components organized by domain\n│   ├── graphs/        # Pixi.js run graph rendering engine (ported from @prefecthq/graphs)\n│   ├── hooks/         # Custom hooks for common patterns\n│   ├── lib/           # Utility functions and shared code\n│   ├── mocks/         # Mock data factories\n│   ├── routes/        # Tanstack Router route definitions\n│   ├── storybook/     # Storybook utilities and decorators\n│   └── utils/         # Helper functions and utilities\n├── tests/             # Test utilities and configuration\n├── .storybook/        # Storybook configuration\n└── public/            # Static assets\n```\n\n## Tech Stack\n\n- **React** with TypeScript\n- **Tailwind CSS** - styling\n- **shadcn/ui** - UI component library\n- **Tanstack Query** - API state management\n- **Tanstack Router** - routing\n- **Tanstack Table** - table state management\n- **react-hook-form** - form state management\n- **Recharts** - charts and data visualization\n- **Pixi.js** - WebGL canvas rendering for run graphs (`src/graphs/`)\n- **Vitest** - testing framework\n- **Storybook** - component development and documentation\n- **MSW** - API mocking\n\n## General Principles\n\n- Prefer using functionality from third party libraries over custom implementations\n- Prefer to colocate components in the same file as long as the file is less than 750 lines\n\n## Development Workflow\n\n### Development Process\n\n1. **Start development server**: `npm run dev` (runs on http://localhost:5173/)\n2. **Write tests first** for new components and hooks before implementation\n3. **Implement** the component/hook following existing patterns\n4. **Create Storybook story** to document component variants\n5. **Verify functionality** in the browser at http://localhost:5173/\n6. **Compare with legacy Vue** implementation at http://localhost:4200/ for consistency\n\n### Pre-commit Checklist\n\nBefore committing any changes, always run:\n\n1. **Format and lint**: `npm run check` (Biome formatting and linting)\n2. **Additional linting**: `npm run lint` (ESLint rules)\n3. **Build verification**: `npm run build` (ensure no build errors)\n4. **Test verification**: `npm test` (run relevant tests)\n\n### Performance Tips\n\n- Run **single tests** for faster feedback: `npm test -- ComponentName`\n- Run **lint on single files** for performance: `npx eslint src/path/to/file.ts --fix`\n- Use **Storybook** for isolated component development: `npm run storybook`\n\n### Browser Testing\n\n- **Primary development**: http://localhost:5173/\n- **Legacy comparison**: http://localhost:4200/\n- **Component documentation**: http://localhost:6006/ (Storybook)\n\n## Common Commands\n\n- `npm run dev` - Start development server\n- `npm run build` - Build production bundle\n- `npm run test` - Run tests\n- `npm run check` - Run linter and formatter (Biome)\n- `npm run lint` - Run ESLint\n- `npm run storybook` - Start Storybook\n- `npm run service-sync` - Sync API types from backend\n\n## Code Organization\n\n- **Flat structure**: Components, tests, and stories live together\n- **Index exports**: Each directory exports public APIs via `index.ts`\n- **Domain organization**: Components organized by Prefect domain (flows, deployments, etc.)\n- **Namespace awareness**: Component names consider their directory context\n\n## Quality Standards\n\n- **Always write tests** for new components and hooks\n- **Always create Storybook stories** for new components\n- **Run `npm run check`** after creating components/hooks\n- **Check functionality** in browser during development\n- **Mock all API calls** using MSW\n\n## API Integration\n\n- Use **`useSuspenseQuery`** over `useQuery` for declarative code; use `useQuery` when the component must silently return `null` while loading rather than suspend the tree (e.g., optional or promotional components that should disappear rather than show a skeleton)\n- **Query factories** in `/api` directories with standardized key patterns\n- **Mutation hooks** in `/api` directories\n- **No data transformation** in query factories - do it in components\n- **Duration fields** (`estimated_run_time`, `total_run_time`, etc.) are returned in **seconds** by the API. Prefer `secondsToApproximateString`/`secondsToString` from `@/utils/seconds` for display — they take raw seconds directly. `humanizeDuration` and similar JS libraries expect milliseconds instead, so multiply by 1000 before passing to them\n\n## Forms\n\n- **react-hook-form** for form state\n- **zod** for validation\n- **Form** and **FormField** components from shadcn/ui\n- **Stepper** component for wizard flows\n- **Forms bound to refetched queries**: Entity queries (deployments, etc.) refetch on a 30-second interval and on window focus, returning new object references each time. Use `useState` lazy initializers to capture default values once — do not sync form state via `useEffect`, which overwrites in-flight user edits on every refetch. Add `key={entity.id}` on the form component so it fully resets when the entity changes.\n- **Zod v4**: `z.record()` requires an explicit key schema — `z.record(z.string(), z.unknown())`, not the v3-style `z.record(z.unknown())`. `ZodError` instances expose `.issues`, not the removed `.errors`.\n\n## Testing\n\n- **Vitest** with **@testing-library/react**\n- All API calls mocked with **MSW**\n- Mock factories using **@ngneat/falso**\n- Run single tests for performance: `npm test -- ComponentName`\n\n## Git Workflow\n\n- Branch naming: `ui-v2/feature-description`\n- Succinct commit messages\n- PR descriptions mention \"Related to #15512\"\n- Never commit directly to `main`\n\n## Styling for Light and Dark Mode\n\nThe UI supports both light and dark themes. To ensure components render correctly in both modes:\n\n### Use Semantic Color Tokens\n\nAlways use Tailwind's semantic color classes that automatically adapt to the current theme instead of hardcoded color values:\n\n| Instead of | Use |\n|------------|-----|\n| `bg-gray-100`, `bg-gray-200` | `bg-muted` |\n| `bg-white` | `bg-background` or `bg-card` |\n| `text-gray-500`, `text-gray-600` | `text-muted-foreground` |\n| `text-gray-900`, `text-black` | `text-foreground` |\n| `border-gray-200`, `border-gray-300` | `border-border` or `border-muted` |\n\n### For Dividers and Subtle Elements\n\nUse opacity modifiers with semantic colors for subtle visual elements like dividers:\n- `bg-muted-foreground/30` for subtle divider lines\n- `border-border` for standard borders\n\n### Prose Content in Dark Mode\n\nTailwind's `prose` class (`@tailwindcss/typography`) does **not** automatically invert in dark mode. Any element using `prose` must also include `dark:prose-invert`:\n\n```tsx\n<div className=\"prose dark:prose-invert\">...</div>\n```\n\n### CodeMirror Editors\n\n`@uiw/react-codemirror` does not follow the app theme automatically. Any component using `useCodeMirror` must explicitly read and pass the theme:\n\n```tsx\nconst { resolvedTheme } = useTheme(); // from \"next-themes\"\nuseCodeMirror({ theme: resolvedTheme === \"dark\" ? \"dark\" : \"light\", ... });\n```\n\n### Avoid Hardcoded Colors\n\nNever use hardcoded gray scale colors (e.g., `bg-gray-100`, `text-gray-500`) as these will not adapt to dark mode and can make text unreadable or create jarring visual contrast.\n\n### Testing Dark Mode\n\nAlways verify components in both light and dark mode:\n1. Use the theme toggle in Settings to switch between modes\n2. Check that all text remains readable\n3. Verify backgrounds blend appropriately with the overall theme\n4. Ensure sufficient contrast for interactive elements\n\n## Architecture Notes\n\n- **Suspense-first**: Use suspense queries to avoid loading states\n- **Type safety**: Never use `as unknown` or disable ESLint\n- **Pure functions**: Keep utilities side-effect free\n- **Composition**: Prefer composition over complex inheritance\n","tests/AGENTS.md":"# Test Suite\n\nTests for all Prefect components. Directory structure mirrors `src/prefect/`.\n\n## Key Contracts\n\n- **Server and client test fixtures should not mix.** Server-side tests use a stripped-down client. Do not use `prefect_client` (the full client fixture) in server tests.\n- **Prefer real operations over mocks.** Use real flows, deployments, and flow runs where possible. Reserve `unittest.mock` for external services and time-sensitive operations.\n- **Tests must be deterministic.** No reliance on timing, ordering, or external state.\n- **Both SQLite and PostgreSQL are tested in CI.** Database-related tests run against both.\n\n## Essential Commands\n\n```bash\nuv run pytest tests/                          # Run all tests\nuv run pytest tests/path.py -k test_name      # Run specific test\nuv run pytest tests/module/ -n4               # Run in parallel\nuv run pytest tests/path.py -x                # Stop on first failure\nuv run pytest tests/path.py -x --tb=short     # Compact tracebacks\n```\n\n## Important Fixtures\n\nShared fixtures live in `fixtures/` (see fixtures/AGENTS.md) and root `conftest.py`. The key distinction:\n\n- **Client-side tests** use `prefect_client` (full SDK client). Do not use in server tests.\n- **Server API tests** use `client` / `test_client` (raw httpx/FastAPI against an ephemeral server)\n- **Server model/orchestration tests** use `session` (async SQLAlchemy) and pre-built ORM fixtures (`flow`, `flow_run`, `task_run`, `deployment`, etc.)\n- `test-projects/` — Sample projects used by CLI/deploy tests\n\n## Testing Guidelines\n\n### Database isolation\n\nTests do not get a clean database by default. If a test depends on the DB starting empty — it counts rows, lists \"all X\", or asserts on the absence of records — opt in with `@pytest.mark.clear_db`:\n\n```python\n@pytest.mark.clear_db                # per-test\nasync def test_count_flows(): ...\n\nclass TestFlowAPI:                   # per-class\n    pytestmark = pytest.mark.clear_db\n\npytestmark = pytest.mark.clear_db    # whole module\n```\n\nTests that create resources with UUID-randomized names, filter by IDs they own, or only interact with responses they create themselves usually do not need this marker. Skipping the clear yields a 25–100% suite speedup, so prefer not adding it unless required.\n\nTo check whether a marked file still needs the marker, run it with `--no-clear-db`:\n\n```bash\nuv run pytest tests/path/to/file.py --no-clear-db -x\n```\n\nIf it passes, delete the `pytestmark` (or per-test marker) and commit.\n\n### PREFECT_HOME cleanup\n\n`PREFECT_HOME` is a single temp directory created once per test session (`pytest_sessionstart`), not reset between tests. A test that writes a file directly into it (e.g. a PID file) must delete it in fixture teardown, or later tests in the same session can see it as real state.\n\n### Event assertions\n\nCreating a domain object emits a lifecycle event: building a `flow`, `work_pool`, `variable`, block, concurrency limit, etc. (via fixture or model call) emits `prefect.<object>.{created,...}`. Server tests that assert on `AssertingEventsClient` totals or ordering must `AssertingEventsClient.reset()` after fixture setup, so they count only the events from the action under test rather than the events emitted while building fixtures.\n\n### Type Hints\n- Full type hints on all test functions and fixtures (Python >=3.12 style: `dict[str, str]`)\n- Return type hints on fixtures, omit `-> None` on test functions\n\n### Mocking Strategy\n- Use `unittest.mock` only when necessary (external services, time-sensitive operations)\n- Use `respx` for HTTP response mocking\n\n### Flaky Tests\nWe have a workflow that identifies and fixes tests that flake after merging to main. Check CI test output to see which tests are currently slow or flaky.\n\n**Flow timeout tests**: `pytest-timeout` defaults to SIGALRM on Unix, which interferes with Prefect's own SIGALRM-based flow timeout mechanism. Any test that exercises flow timeouts must opt into thread-based timeouts:\n```python\n@pytest.mark.timeout(method=\"thread\")  # alarm-based pytest-timeout will interfere\nasync def test_flows_fail_with_timeout(self): ...\n```\n\nWhen combining `timeout_seconds` flows with concurrency, use a generous timeout (≥ 2s): the heartbeat-thread setup runs inside the flow's timeout scope and can exhaust a tight timeout before the flow body starts, causing pre-`yield` cancellation on contended CI runners.\n\nUse `retry_asserts` from `prefect._internal.testing` to handle timing-sensitive assertions. Two patterns:\n\n- **Retrying assertions for async event propagation** (most common): wrap the assertion inside `with attempt:` so it retries until the event arrives.\n  ```python\n  async for attempt in retry_asserts(max_attempts=5, delay=0.5):\n      with attempt:\n          callback.assert_called_once_with(flow_run_id)\n  ```\n- **Retrying HTTP requests** (`hosted_api_client` tests): SQLite \"database is locked\" 503 errors can occur due to concurrent access. Retry the HTTP request inside the loop; keep the result assertions *outside* so a wrong result is never masked.\n\n## Related\n\n- `src/prefect/testing/` → Test utilities shipped with the SDK\n- `integration-tests/` → End-to-end tests requiring a running server\n- `ui-v2/e2e/` → Playwright UI tests (see ui-v2/e2e/AGENTS.md)\n",".claude/skills/write-docs/template-howto.mdx":"# Claude Directive: template-howto.mdx\n\nPath: `.claude/skills/write-docs/template-howto.mdx`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/.claude/skills/write-docs/template-howto.mdx)"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"Prefect is a workflow orchestration platform that coordinates and observes data pipelines. It provides a Python SDK for building workflows, a server backend for orchestration, and a web-based UI for managing and monitoring workflows.\n\n# Guiding Principles\n\nYour primary responsibility is to the project and its users. Every change should serve the broader user base — not just the immediate request. Be a quality gate: prefer correct, minimal, well-tested changes over fast ones.\n\n# Before You Start\n\nBefore making code changes, read the public contribution guide in `docs/contribute/dev-contribute.mdx` so your work follows Prefect's contribution expectations, design principles, AI-use policy, testing standards, and maintainer review criteria.\nFor documentation-only changes, also read `docs/contribute/docs-contribute.mdx`.\nFor integration changes, also read `docs/contribute/contribute-integrations.mdx`.\n\n# Directory Structure\n\n```\nprefect/\n├── benches/                         # Benchmarks (CLI, flows, tasks, imports)\n├── client/                          # prefect-client build: subset of src/prefect/ published as a separate PyPI package\n├── compat-tests/                    # Tests for REST API compatibility with Prefect Cloud\n├── Dockerfile                       # Production container image\n├── docs/                            # Mintlify documentation (see docs/AGENTS.md)\n├── examples/                        # Example flows (auto-published to docs)\n├── formal/                          # Executable formal models (see formal/tla/AGENTS.md)\n├── integration-tests/               # End-to-end integration tests (require running server)\n├── justfile                         # Task runner (just <command>)\n├── load_testing/                    # Load/performance testing\n├── plans/                           # Design/implementation plan documents\n├── pyproject.toml                   # Root package config\n├── schemas/                         # JSON schemas (prefect.yaml, settings)\n├── scripts/                         # Code generation and release scripts\n├── src/\n│   ├── integrations/                # External service integrations (see src/integrations/AGENTS.md)\n│   └── prefect/                     # Core package: SDK, server, CLI (see src/prefect/AGENTS.md)\n├── tests/                           # Test suite, mirrors src/prefect/ (see tests/AGENTS.md)\n├── tools/                           # Build tools\n├── ui/                              # Vue UI (legacy, will be replaced by ui-v2)\n├── ui-v2/                           # React UI rewrite (see ui-v2/AGENTS.md)\n└── uv.lock                          # Lockfile (auto-generated, do not edit manually)\n```\n\n# Essential Commands\n\n```bash\n# Dependencies\nuv sync                                # Install all dev dependencies\njust install                           # Same as above, plus perf group\n\n# Running code\nuv run -s my_script.py                             # Run a script with an editable prefect install\nuv run --extra aws repros/1234.py                  # Run repro needing an integration extra\nuv run --project ./src/integrations/<name> <cmd>   # Run against a local integration from repo root\nprefect server start                               # Start local server\nprefect config view                                # Inspect current configuration\n\n# Testing (see tests/AGENTS.md for full details)\nuv run pytest tests/path.py -k name    # Run specific test\nuv run pytest tests/path.py -x -n4     # Parallel, stop on first failure\n\n# Linting & formatting\nuv run ruff check --fix .              # Lint with auto-fix\nuv run ruff format .                   # Format code\nuv run pre-commit run --all-files      # Run all pre-commit hooks\n\n# Docs (from repo root)\njust docs                              # Start Mintlify dev server at localhost:3000\njust generate-docs                     # Regenerate all doc artifacts\n\n# UI (from repo root)\njust ui-v2                             # Start React dev server at localhost:5173\n\n# Docker\ndocker build -t prefect .                              # Default build (Python 3.11)\ndocker build --build-arg PYTHON_VERSION=3.12 -t prefect .  # Custom Python version\ndocker build --build-arg EXTRA_PIP_PACKAGES=\"prefect-aws\" -t prefect .  # With extras\n```\n\n## Quick Reference\n\n| Component | Path | Tests |\n|-----------|------|-------|\n| Core SDK (flows, tasks, states, deployments) | `src/prefect/` | `tests/` |\n| Flow & task engines (async orchestration) | `src/prefect/flow_engine.py`, `task_engine.py` | `tests/engine/` |\n| Client SDK (schemas, HTTP client) | `src/prefect/client/` | `tests/client/` |\n| Server (API, database, scheduling) | `src/prefect/server/` | `tests/server/` |\n| CLI | `src/prefect/cli/` | `tests/cli/` |\n| Settings | `src/prefect/settings/` | `tests/settings/` |\n| Integrations (`prefect-aws`, `prefect-dbt`, etc.) | `src/integrations/` | per-integration |\n| React UI (replacing Vue `ui/`) | `ui-v2/` | `ui-v2/e2e/` |\n\n## Tech Stack & Tooling\n\n- **Python >=3.11,<3.16** with modern typing (`list[int]`, `T | None`)\n- **FastAPI** for REST APIs\n- **Pydantic v2** for validation\n- **SQLAlchemy 2.0** async ORM\n- **Alembic** for database migrations\n- **PostgreSQL/SQLite** databases\n- **React + TypeScript** for UI (see ui-v2/AGENTS.md)\n- **Ruff** for linting and formatting\n- **Pre-commit** hooks: ruff, codespell, mypy (partial), uv-lock, no-commit-to-branch\n\n## Architecture Overview\n\n- **Three user-facing surfaces**: Python SDK (`@flow`/`@task` decorators), CLI (`prefect` command), REST API (FastAPI server)\n- **Server is the source of truth for flow state transitions** — the flow engine proposes states, and the server's orchestration layer accepts or rejects them. Task state transitions are managed locally by the task engine via `set_state` and communicated through `prefect.task_run.*` events\n- **Two published packages**: `prefect` (full SDK + server) and `prefect-client` (lightweight client subset). `client/` contains the build config that selects which files from `src/prefect/` go into `prefect-client`\n- **Integrations are separate PyPI packages** (`prefect-aws`, `prefect-dbt`, etc.) each with their own version, published independently from `src/integrations/`\n- **Async-first execution model** with sync wrappers — the engines (`flow_engine.py`, `task_engine.py`) are async; sync `@flow`/`@task` functions are run in workers\n\n## Anti-patterns\n\n- **Never bypass the server for flow state transitions** — always go through the orchestration API, even in tests. Task state transitions are managed locally by the task engine by design\n- **Never use `pip install` or `uv pip`** — use `uv` for all dependency management\n- **Never use deferred imports** (imports inside functions) unless required to break circular imports or for optional dependencies\n- **Never commit directly to `main`** — a pre-commit hook enforces this\n- **Never skip pre-commit hooks** (`--no-verify`) — fix the underlying issue instead\n- **Never amend commits** (`--amend`) — create new commits instead\n\n# Development Guidelines\n\n## Make sure you have a Prefect server or Prefect Cloud\n- use `prefect config view` to check your current profile\n- run `prefect server start` in the background if needed\n\n## Code Conventions\n\n- Private implementation details (`_private_method`)\n- No public API changes without approval\n- Use single backticks for inline code references in docstrings, not double backticks\n\n## Testing\n\n- Directory structure mirrors source code\n- Run affected tests after changes: `uv run pytest tests/module/`\n- Tests require deterministic behavior\n- Mock external dependencies\n\n## Formal Protocol Models\n\n- Use TLA+ selectively for bounded concurrent or distributed protocols whose correctness depends on interleavings, retries, duplication, time, or ownership. Prefer ordinary tests for local or sequential behavior.\n- Treat each `formal/tla/<protocol>/README.md` as the authority for its scope, configurations, action-to-code mapping, owner, and review triggers.\n- Before changing mapped behavior, review the model and its deterministic regressions. Update them when the abstraction changes; otherwise state in the PR why it remains valid.\n- A green model validates only its documented abstraction, not Prefect's implementation. Implementation evidence comes from mapped behavior and contract tests.\n\n## Working on Issues\n\n- Read the GitHub issue/PR and comments (`gh issue view`, `gh pr view`) before writing code\n- Understand the scope and intended behavior — ask clarifying questions if unclear\n- Create reproduction scripts in `repros/` directory (create it if needed; add to `.gitignore`)\n- Name files by issue number: `repros/1234.py` (only create one file per issue)\n- Ensure the issue is reproducible before fixing\n- Add unit tests for fixes\n- DO NOT delete files from `repros/` directory after reproducing the issue unless asked\n\n## PR Body Style\n\n- Start with \"closes #1234\" if resolving issue\n- Brief summary: \"this PR {changes}\"\n- Details in `<details>` tag\n- Include relevant links\n\n## Code Review Rules\n\nWhen reviewing changes, read and apply [REVIEW.md](REVIEW.md).\n\n# Project Practices\n\n- All PRs require test coverage for new functionality\n- GitHub issues are used for tracking issues (use the `gh` cli)\n- Dependencies: updates to client-side deps in `pyproject.toml` require parallel changes in `client/pyproject.toml`\n- AGENTS.md always symlinked to CLAUDE.md\n","isInternal":false,"tokens":2171,"sizeBytes":9565},{"name":"AGENTS.md","path":"client/AGENTS.md","rawUrl":"https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/client/AGENTS.md","title":"client - AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# prefect-client Package Build\n\nBuild configuration for `prefect-client`, a lightweight subset of `prefect` published as a separate PyPI package. This directory does **not** contain source code — it selects files from `src/prefect/` and repackages them.\n\n## Key Contracts\n\n- **Dependency changes in root `pyproject.toml` that affect client-side code must be mirrored in `client/pyproject.toml`.** This is the most common source of build failures.\n- **New imports in `src/prefect/` can break this build** if they pull in server-only dependencies. The build strips server code, so any import that reaches `server/database`, `server/models`, etc. from client-side code will fail.\n- **The build is tested automatically on every PR** via `.github/workflows/prefect-client.yaml`.\n\n## How It Works\n\n`build_client.sh` copies `src/prefect/` into a temp directory, **deletes** server-only and CLI code, then builds with `client/pyproject.toml`. The resulting package has the same version as `prefect` but fewer dependencies.\n\n### What gets removed\n\n- `cli/` — entire CLI\n- `server/` — database, models, orchestration, schemas, services, utilities (keeps only `server/api/`)\n- `deployments/recipes/` and `deployments/templates/`\n- `testing/`\n\n## Build Triggers\n\n- **PR created** — CI builds and smoke-tests\n- **GitHub release published** — CI builds and publishes to PyPI (same version as `prefect`)\n- **Manual** — `bash client/build_client.sh`\n\nIf the CI build fails, reproduce locally with `bash client/build_client.sh` and run the smoke tests (`client_flow.py`, `client_deploy.py`).\n\n## Related\n\n- `src/prefect/client/` → Actual client SDK source code\n- Root `pyproject.toml` → Must stay in sync with `client/pyproject.toml` for shared dependencies\n","isInternal":false,"tokens":421,"sizeBytes":1757},{"name":"AGENTS.md","path":"docs/AGENTS.md","rawUrl":"https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/docs/AGENTS.md","title":"docs - AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Prefect Documentation\n\nStructural context for any agent working in `docs/`. For the full writing guide (page types, components, code testing, style), use the `/write-docs` skill.\n\n## Platform\n\n[Mintlify](https://mintlify.com/) docs published to [docs.prefect.io](https://docs.prefect.io). All files use `.mdx` (Markdown + JSX). Site config lives in `docs/docs.json`.\n\n## Directory structure\n\n```\ndocs/\n  v3/                     # Primary docs for Prefect 3.x\n    get-started/          # Installation, quickstart\n    concepts/             # Core concepts (flows, tasks, states, deployments, etc.)\n    how-to-guides/        # Practical guides organized by category\n    advanced/             # Advanced topics\n    examples/             # Auto-generated from examples/ Python files — do NOT edit directly\n    api-ref/              # API reference — mix of auto-generated and hand-authored\n      python/             # SDK reference (auto-generated — do NOT edit directly)\n      cli/                # CLI command reference (auto-generated — do NOT edit directly)\n      rest-api/           # REST API docs (server/ and cloud/) — endpoint pages auto-generated; index.mdx overview pages are hand-authored\n      events/             # Events reference catalog — hand-authored, editable\n    release-notes/        # Version release notes\n    img/                  # Images organized by section\n  integrations/           # Integration-specific docs (prefect-aws, prefect-gcp, etc.)\n  contribute/             # Contributor guides\n  snippets/               # Reusable MDX snippets imported across pages\n  images/                 # Legacy images\n  logos/                  # Brand assets\n  styles/                 # Vale linting styles\n  resources/              # Unlisted pages (hidden: true) outside the v3/ versioning tree\n```\n\n## Auto-generated content — do not edit\n\n- `v3/examples/` — generated from top-level `examples/` Python files by `generate_example_pages.py`\n- `v3/api-ref/python/`, `v3/api-ref/cli/` — generated API reference (Python SDK, CLI)\n- `v3/api-ref/rest-api/` — individual endpoint pages are auto-generated; the `index.mdx` files at `rest-api/` and `rest-api/server/` are hand-authored and may be edited\n- `v3/api-ref/events/` is **hand-authored** and should be edited directly when event schemas change\n- `integrations/<name>/api-ref/` — generated per-integration API reference via `mdxify` (e.g., `integrations/prefect-kubernetes/api-ref/`); regenerated on each integration release\n\n## File format\n\nEvery `.mdx` file starts with YAML frontmatter:\n\n```yaml\n---\ntitle: Page Title\ndescription: Brief description for SEO and navigation\nsidebarTitle: Optional shorter sidebar label   # optional\nicon: icon-name                                # optional, Mintlify icon\nmode: wide                                     # optional; use \"custom\" for raw JSX/HTML layouts\nhidden: true                                   # optional; unlisted page — no nav registration needed\nkeywords: [\"keyword1\", \"keyword2\"]             # optional, for search\n---\n```\n\nFrontmatter keys are always lowercase. The `title` renders as the page's H1, so start body content at `##` — do not add another H1.\n\n## Navigation\n\nAll pages must be registered in `docs/docs.json` under `navigation.tabs`. When adding a page, add its path (without `.mdx` extension) to the appropriate group.\n\n## Links\n\nUse absolute paths from the docs root without `.mdx`:\n\n```mdx\nSee the [flows documentation](/v3/concepts/flows) for details.\n```\n\nDo not use relative paths or include `.mdx` in links.\n\n## Redirects\n\nWhen renaming or moving a page, add a redirect in `docs/docs.json` `redirects` array so existing links continue to work. Never remove existing redirects unless you are certain the old URL has no inbound traffic. Paths should not include `.mdx`.\n\n## Terminology and casing\n\nPreferred terms are enforced by Vale via `docs/styles/CustomStyles/WordList.yml`. Key entries:\n\n- \"Prefect Cloud\" (not \"Prefect cloud\")\n- \"Prefect server\" (not \"Prefect Server\")\n- \"infrastructure\" (not \"infra\")\n- \"Kubernetes\" (not \"k8s\")\n- \"open source\" (not \"open-source\")\n\n## Versioning\n\nAll new content goes in `docs/v3/`. Do not create pages outside `v3/` for current Prefect 3.x features. Exception: unlisted pages (`hidden: true`) can live in `docs/resources/`.\n\n## Local development\n\n```bash\njust docs     # Start the dev server at localhost:3000\njust links    # Check for broken links\njust lint     # Run Vale linter\n```\n\n## Key rules\n\n1. **Do not edit auto-generated files.** Pages under `v3/examples/`, `v3/api-ref/python/`, `v3/api-ref/cli/`, `v3/api-ref/rest-api/`, and `integrations/<name>/api-ref/` are generated from source code. The exception is `v3/api-ref/events/`, which is hand-authored and should be edited when event schemas change.\n2. **Register new pages in `docs/docs.json`.** An unregistered page won't appear in navigation. Exception: pages with `hidden: true` are unlisted and do not require navigation registration.\n3. **Use `.mdx` extension** for all new documentation files.\n4. **Use Mintlify components** (`<Note>`, `<Tabs>`, `<Steps>`, etc.) rather than Markdown-native admonition syntax.\n5. **Keep code examples working.** They are tested in CI via `pytest-markdown-docs`. Two skip mechanisms exist:\n   - Per-block: add `{/* pmd-metadata: notest */}` above the fenced code block when a single example can't run in isolation.\n   - Per-file: add the path to `SKIP_FILES` in `docs/conftest.py` when an entire page requires real external infrastructure (a live database, a dbt project and profiles, real API credentials). Integration pages almost always fall into this category.\n6. **Use absolute link paths** without file extensions (e.g., `/v3/concepts/flows`).\n7. **Check for existing snippets** in `snippets/` before duplicating content.\n8. **Start body content at `##`.** The frontmatter `title` renders as H1; do not add another H1 in the body.\n9. **Document and mark Cloud-only features.** Some features are only available in Prefect Cloud and have no open source equivalent (SSO, audit logs, incidents, SLAs, the `send-email-notification` automation action, etc.). These originate in the `nebula` repo, so they are documented by Prefect staff and agents rather than external contributors. Make sure they are documented here and marked so customers and downstream consumers (such as the Terraform provider and SDKs) can discover them. Conventions:\n   - **Where Cloud-only guides live.** Account, workspace, and user management guides live under `v3/how-to-guides/cloud/`. Prefer this location for new Cloud-only how-to content.\n   - **Mark the feature** when it appears on a page that also covers open source behavior (for example a shared concept page), so readers can tell the editions apart. Use one of:\n     - A Cloud badge on its own line, directly above the page or section it marks: `<span class=\"badge cloud\"></span>`. It renders a standalone \"Prefect Cloud\" label and the span is intentionally empty; put a blank line before the following prose so it scopes the whole section rather than a single sentence.\n     - A `<Note>This action is only available in Prefect Cloud.</Note>` callout for inline cases (e.g. a single table row or variable).","isInternal":false,"tokens":1694,"sizeBytes":7255},{"name":"AGENTS.md","path":"integration-tests/AGENTS.md","rawUrl":"https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/integration-tests/AGENTS.md","title":"integration-tests - AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Integration Tests\n\nEnd-to-end tests that require a live Prefect server and verify the full orchestration pipeline across process boundaries.\n\n## Purpose & Scope\n\nThese tests cover scenarios that unit tests cannot: real server ↔ worker communication, subprocess flow execution, cancellation across process boundaries, event delivery, and scheduling statefulness.\n\nThey do NOT duplicate unit tests in `tests/`. If a behavior can be tested in isolation, it belongs there.\n\n## Running\n\n```bash\n# Integration tests are excluded from the default testpaths in pyproject.toml — they will NOT run with uv run pytest tests/\nuv run pytest integration-tests/\nuv run pytest integration-tests/test_nested_cancellation.py\n```\n\nRequirements:\n- `PREFECT_API_URL` must point to a running Prefect server (check with `prefect config view`)\n- `uv` must be available in `PATH`\n\nSome tests accept additional env vars: `SERVER_VERSION` (skip version-specific tests), `PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE`, `PREFECT_API_AUTH_STRING`.\n\n## Structure\n\nNo shared `conftest.py`. Each test file is self-contained with its own helpers and fixtures inline. There are no pytest fixtures shared across files.\n\n## Usage Patterns\n\n**Poll, don't assert synchronously.** Hook execution, state transitions, and marker-file writes are independent side effects of the same cancel/complete sequence — the API state can become visible before the hook's file is written. Use `_wait_for()` instead of a bare `assert`:\n\n```python\n# Wrong — races on rare timing:\nassert Path(marker_dir, HOOK_MARKER).exists()\n\n# Right — polls until satisfied or timeout:\n_wait_for(\n    lambda: Path(marker_dir, HOOK_MARKER).exists(),\n    timeout=30,\n    message=\"Hook did not write its marker.\\n\" + _worker_output(log_path),\n)\n```\n\n**Marker files for cross-process state.** Flows running in subprocesses write files to a shared `tmp_path` to signal that a state was reached. Name markers with constants (`PARENT_HOOK_MARKER`, `CHILD_STARTED_MARKER`, etc.) and document them at the top of the file.\n\n**Subprocess invocations use `uv --isolated`.** All CLI calls go through `uv.find_uv_bin()` with `--isolated` to get a clean environment:\n\n```python\nsubprocess.run([uv.find_uv_bin(), \"run\", \"--isolated\", \"prefect\", \"worker\", \"start\", ...])\n```\n\n`PREFECT_API_URL` is inherited from the calling process's env — it still needs to be set.\n\n**Unique work pool names.** Always suffix with `uuid4()` to avoid conflicts across parallel test runs.\n\n**Explicit cleanup in `finally`.** Deployments, work pools, and subprocesses must be cleaned up manually — there is no pytest fixture teardown:\n\n```python\ntry:\n    # set up pool, deployment, worker, run assertions\nfinally:\n    client.delete_work_pool(pool_name)\n    proc.terminate()\n    try:\n        proc.wait(timeout=5)\n    except subprocess.TimeoutExpired:\n        proc.kill()\n```\n\n## Anti-Patterns\n\n- Don't assert synchronously on hook markers or other side effects right after triggering a cancellation — always poll.\n- Don't use fixed `asyncio.sleep()` delays as a substitute for `_wait_for()` — they either waste time or still race.\n- Don't share state between test files via module-level globals — each file is standalone.\n- Don't use subprocess CLI for infrastructure setup/teardown (work pool CRUD, deployment creation) — use `get_client(sync_client=True)` API calls instead. Subprocess is only for testing cross-process behavior (starting workers, executing flow runs in a separate process).\n\n## Pitfalls\n\n- `PREFECT_API_URL` not set produces cryptic errors, not a helpful configuration message. Check it first.\n- These tests are slow (seconds to minutes per test) and intentionally excluded from the default `testpaths` in `pyproject.toml`.\n- Process `terminate()` sends SIGTERM but the subprocess may not exit immediately — always `wait(timeout=...)` and fall back to `kill()`.\n- WebSocket event subscriptions are not active until the `async with get_events_subscriber(...)` context establishes the server connection — events emitted before that happens are silently lost. Signal readiness from *inside* the subscription context using a `threading.Event`, and `assert ready.wait(timeout=30)` before triggering any events in the test.\n","isInternal":false,"tokens":924,"sizeBytes":4253},{"name":"AGENTS.md","path":"tests/AGENTS.md","rawUrl":"https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/tests/AGENTS.md","title":"tests - AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Test Suite\n\nTests for all Prefect components. Directory structure mirrors `src/prefect/`.\n\n## Key Contracts\n\n- **Server and client test fixtures should not mix.** Server-side tests use a stripped-down client. Do not use `prefect_client` (the full client fixture) in server tests.\n- **Prefer real operations over mocks.** Use real flows, deployments, and flow runs where possible. Reserve `unittest.mock` for external services and time-sensitive operations.\n- **Tests must be deterministic.** No reliance on timing, ordering, or external state.\n- **Both SQLite and PostgreSQL are tested in CI.** Database-related tests run against both.\n\n## Essential Commands\n\n```bash\nuv run pytest tests/                          # Run all tests\nuv run pytest tests/path.py -k test_name      # Run specific test\nuv run pytest tests/module/ -n4               # Run in parallel\nuv run pytest tests/path.py -x                # Stop on first failure\nuv run pytest tests/path.py -x --tb=short     # Compact tracebacks\n```\n\n## Important Fixtures\n\nShared fixtures live in `fixtures/` (see fixtures/AGENTS.md) and root `conftest.py`. The key distinction:\n\n- **Client-side tests** use `prefect_client` (full SDK client). Do not use in server tests.\n- **Server API tests** use `client` / `test_client` (raw httpx/FastAPI against an ephemeral server)\n- **Server model/orchestration tests** use `session` (async SQLAlchemy) and pre-built ORM fixtures (`flow`, `flow_run`, `task_run`, `deployment`, etc.)\n- `test-projects/` — Sample projects used by CLI/deploy tests\n\n## Testing Guidelines\n\n### Database isolation\n\nTests do not get a clean database by default. If a test depends on the DB starting empty — it counts rows, lists \"all X\", or asserts on the absence of records — opt in with `@pytest.mark.clear_db`:\n\n```python\n@pytest.mark.clear_db                # per-test\nasync def test_count_flows(): ...\n\nclass TestFlowAPI:                   # per-class\n    pytestmark = pytest.mark.clear_db\n\npytestmark = pytest.mark.clear_db    # whole module\n```\n\nTests that create resources with UUID-randomized names, filter by IDs they own, or only interact with responses they create themselves usually do not need this marker. Skipping the clear yields a 25–100% suite speedup, so prefer not adding it unless required.\n\nTo check whether a marked file still needs the marker, run it with `--no-clear-db`:\n\n```bash\nuv run pytest tests/path/to/file.py --no-clear-db -x\n```\n\nIf it passes, delete the `pytestmark` (or per-test marker) and commit.\n\n### PREFECT_HOME cleanup\n\n`PREFECT_HOME` is a single temp directory created once per test session (`pytest_sessionstart`), not reset between tests. A test that writes a file directly into it (e.g. a PID file) must delete it in fixture teardown, or later tests in the same session can see it as real state.\n\n### Event assertions\n\nCreating a domain object emits a lifecycle event: building a `flow`, `work_pool`, `variable`, block, concurrency limit, etc. (via fixture or model call) emits `prefect.<object>.{created,...}`. Server tests that assert on `AssertingEventsClient` totals or ordering must `AssertingEventsClient.reset()` after fixture setup, so they count only the events from the action under test rather than the events emitted while building fixtures.\n\n### Type Hints\n- Full type hints on all test functions and fixtures (Python >=3.12 style: `dict[str, str]`)\n- Return type hints on fixtures, omit `-> None` on test functions\n\n### Mocking Strategy\n- Use `unittest.mock` only when necessary (external services, time-sensitive operations)\n- Use `respx` for HTTP response mocking\n\n### Flaky Tests\nWe have a workflow that identifies and fixes tests that flake after merging to main. Check CI test output to see which tests are currently slow or flaky.\n\n**Flow timeout tests**: `pytest-timeout` defaults to SIGALRM on Unix, which interferes with Prefect's own SIGALRM-based flow timeout mechanism. Any test that exercises flow timeouts must opt into thread-based timeouts:\n```python\n@pytest.mark.timeout(method=\"thread\")  # alarm-based pytest-timeout will interfere\nasync def test_flows_fail_with_timeout(self): ...\n```\n\nWhen combining `timeout_seconds` flows with concurrency, use a generous timeout (≥ 2s): the heartbeat-thread setup runs inside the flow's timeout scope and can exhaust a tight timeout before the flow body starts, causing pre-`yield` cancellation on contended CI runners.\n\nUse `retry_asserts` from `prefect._internal.testing` to handle timing-sensitive assertions. Two patterns:\n\n- **Retrying assertions for async event propagation** (most common): wrap the assertion inside `with attempt:` so it retries until the event arrives.\n  ```python\n  async for attempt in retry_asserts(max_attempts=5, delay=0.5):\n      with attempt:\n          callback.assert_called_once_with(flow_run_id)\n  ```\n- **Retrying HTTP requests** (`hosted_api_client` tests): SQLite \"database is locked\" 503 errors can occur due to concurrent access. Retry the HTTP request inside the loop; keep the result assertions *outside* so a wrong result is never masked.\n\n## Related\n\n- `src/prefect/testing/` → Test utilities shipped with the SDK\n- `integration-tests/` → End-to-end tests requiring a running server\n- `ui-v2/e2e/` → Playwright UI tests (see ui-v2/e2e/AGENTS.md)\n","isInternal":false,"tokens":1214,"sizeBytes":5295},{"name":"AGENTS.md","path":"ui-v2/AGENTS.md","rawUrl":"https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/ui-v2/AGENTS.md","title":"ui-v2 - AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Prefect UI v2 - React Migration\n\nThis is the new React-based Prefect UI, migrating from the legacy Vue application with minimal visual and functional changes.\n\n## Project Structure\n\n```\nprefect/ui-v2/\n├── src/\n│   ├── api/           # API queries, mutations, and mocks\n│   ├── auth/          # Authentication state, AuthProvider, useAuth hook\n│   ├── components/    # React components organized by domain\n│   ├── graphs/        # Pixi.js run graph rendering engine (ported from @prefecthq/graphs)\n│   ├── hooks/         # Custom hooks for common patterns\n│   ├── lib/           # Utility functions and shared code\n│   ├── mocks/         # Mock data factories\n│   ├── routes/        # Tanstack Router route definitions\n│   ├── storybook/     # Storybook utilities and decorators\n│   └── utils/         # Helper functions and utilities\n├── tests/             # Test utilities and configuration\n├── .storybook/        # Storybook configuration\n└── public/            # Static assets\n```\n\n## Tech Stack\n\n- **React** with TypeScript\n- **Tailwind CSS** - styling\n- **shadcn/ui** - UI component library\n- **Tanstack Query** - API state management\n- **Tanstack Router** - routing\n- **Tanstack Table** - table state management\n- **react-hook-form** - form state management\n- **Recharts** - charts and data visualization\n- **Pixi.js** - WebGL canvas rendering for run graphs (`src/graphs/`)\n- **Vitest** - testing framework\n- **Storybook** - component development and documentation\n- **MSW** - API mocking\n\n## General Principles\n\n- Prefer using functionality from third party libraries over custom implementations\n- Prefer to colocate components in the same file as long as the file is less than 750 lines\n\n## Development Workflow\n\n### Development Process\n\n1. **Start development server**: `npm run dev` (runs on http://localhost:5173/)\n2. **Write tests first** for new components and hooks before implementation\n3. **Implement** the component/hook following existing patterns\n4. **Create Storybook story** to document component variants\n5. **Verify functionality** in the browser at http://localhost:5173/\n6. **Compare with legacy Vue** implementation at http://localhost:4200/ for consistency\n\n### Pre-commit Checklist\n\nBefore committing any changes, always run:\n\n1. **Format and lint**: `npm run check` (Biome formatting and linting)\n2. **Additional linting**: `npm run lint` (ESLint rules)\n3. **Build verification**: `npm run build` (ensure no build errors)\n4. **Test verification**: `npm test` (run relevant tests)\n\n### Performance Tips\n\n- Run **single tests** for faster feedback: `npm test -- ComponentName`\n- Run **lint on single files** for performance: `npx eslint src/path/to/file.ts --fix`\n- Use **Storybook** for isolated component development: `npm run storybook`\n\n### Browser Testing\n\n- **Primary development**: http://localhost:5173/\n- **Legacy comparison**: http://localhost:4200/\n- **Component documentation**: http://localhost:6006/ (Storybook)\n\n## Common Commands\n\n- `npm run dev` - Start development server\n- `npm run build` - Build production bundle\n- `npm run test` - Run tests\n- `npm run check` - Run linter and formatter (Biome)\n- `npm run lint` - Run ESLint\n- `npm run storybook` - Start Storybook\n- `npm run service-sync` - Sync API types from backend\n\n## Code Organization\n\n- **Flat structure**: Components, tests, and stories live together\n- **Index exports**: Each directory exports public APIs via `index.ts`\n- **Domain organization**: Components organized by Prefect domain (flows, deployments, etc.)\n- **Namespace awareness**: Component names consider their directory context\n\n## Quality Standards\n\n- **Always write tests** for new components and hooks\n- **Always create Storybook stories** for new components\n- **Run `npm run check`** after creating components/hooks\n- **Check functionality** in browser during development\n- **Mock all API calls** using MSW\n\n## API Integration\n\n- Use **`useSuspenseQuery`** over `useQuery` for declarative code; use `useQuery` when the component must silently return `null` while loading rather than suspend the tree (e.g., optional or promotional components that should disappear rather than show a skeleton)\n- **Query factories** in `/api` directories with standardized key patterns\n- **Mutation hooks** in `/api` directories\n- **No data transformation** in query factories - do it in components\n- **Duration fields** (`estimated_run_time`, `total_run_time`, etc.) are returned in **seconds** by the API. Prefer `secondsToApproximateString`/`secondsToString` from `@/utils/seconds` for display — they take raw seconds directly. `humanizeDuration` and similar JS libraries expect milliseconds instead, so multiply by 1000 before passing to them\n\n## Forms\n\n- **react-hook-form** for form state\n- **zod** for validation\n- **Form** and **FormField** components from shadcn/ui\n- **Stepper** component for wizard flows\n- **Forms bound to refetched queries**: Entity queries (deployments, etc.) refetch on a 30-second interval and on window focus, returning new object references each time. Use `useState` lazy initializers to capture default values once — do not sync form state via `useEffect`, which overwrites in-flight user edits on every refetch. Add `key={entity.id}` on the form component so it fully resets when the entity changes.\n- **Zod v4**: `z.record()` requires an explicit key schema — `z.record(z.string(), z.unknown())`, not the v3-style `z.record(z.unknown())`. `ZodError` instances expose `.issues`, not the removed `.errors`.\n\n## Testing\n\n- **Vitest** with **@testing-library/react**\n- All API calls mocked with **MSW**\n- Mock factories using **@ngneat/falso**\n- Run single tests for performance: `npm test -- ComponentName`\n\n## Git Workflow\n\n- Branch naming: `ui-v2/feature-description`\n- Succinct commit messages\n- PR descriptions mention \"Related to #15512\"\n- Never commit directly to `main`\n\n## Styling for Light and Dark Mode\n\nThe UI supports both light and dark themes. To ensure components render correctly in both modes:\n\n### Use Semantic Color Tokens\n\nAlways use Tailwind's semantic color classes that automatically adapt to the current theme instead of hardcoded color values:\n\n| Instead of | Use |\n|------------|-----|\n| `bg-gray-100`, `bg-gray-200` | `bg-muted` |\n| `bg-white` | `bg-background` or `bg-card` |\n| `text-gray-500`, `text-gray-600` | `text-muted-foreground` |\n| `text-gray-900`, `text-black` | `text-foreground` |\n| `border-gray-200`, `border-gray-300` | `border-border` or `border-muted` |\n\n### For Dividers and Subtle Elements\n\nUse opacity modifiers with semantic colors for subtle visual elements like dividers:\n- `bg-muted-foreground/30` for subtle divider lines\n- `border-border` for standard borders\n\n### Prose Content in Dark Mode\n\nTailwind's `prose` class (`@tailwindcss/typography`) does **not** automatically invert in dark mode. Any element using `prose` must also include `dark:prose-invert`:\n\n```tsx\n<div className=\"prose dark:prose-invert\">...</div>\n```\n\n### CodeMirror Editors\n\n`@uiw/react-codemirror` does not follow the app theme automatically. Any component using `useCodeMirror` must explicitly read and pass the theme:\n\n```tsx\nconst { resolvedTheme } = useTheme(); // from \"next-themes\"\nuseCodeMirror({ theme: resolvedTheme === \"dark\" ? \"dark\" : \"light\", ... });\n```\n\n### Avoid Hardcoded Colors\n\nNever use hardcoded gray scale colors (e.g., `bg-gray-100`, `text-gray-500`) as these will not adapt to dark mode and can make text unreadable or create jarring visual contrast.\n\n### Testing Dark Mode\n\nAlways verify components in both light and dark mode:\n1. Use the theme toggle in Settings to switch between modes\n2. Check that all text remains readable\n3. Verify backgrounds blend appropriately with the overall theme\n4. Ensure sufficient contrast for interactive elements\n\n## Architecture Notes\n\n- **Suspense-first**: Use suspense queries to avoid loading states\n- **Type safety**: Never use `as unknown` or disable ESLint\n- **Pure functions**: Keep utilities side-effect free\n- **Composition**: Prefer composition over complex inheritance\n","isInternal":false,"tokens":1908,"sizeBytes":8171},{"name":"SKILL.md","path":".claude/skills/agents-md-sync/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/.claude/skills/agents-md-sync/SKILL.md","title":"agents-md-sync","category":"anthropic-skill","format":"markdown","content":"---\nname: agents-md-sync\ndescription: Analyze code changes on the current branch and recommend updates to AGENTS.md files that have become stale. Use this skill before creating a PR, when the user asks to check AGENTS.md freshness, or when preparing an AGENTS.md update after a PR merges to main. Trigger whenever the user mentions syncing, updating, or checking AGENTS.md files, or when they're about to create a PR that touches code structure (new modules, renamed directories, changed commands, modified architecture).\n---\n\n# AGENTS.md Sync\n\nDetect when code changes make durable AGENTS.md guidance stale and produce a report with specific recommendations. Treat AGENTS.md files as operating manuals for future agents, not changelogs for recent diffs.\n\n## When to use\n\n- Before creating a PR — check if the branch's changes warrant AGENTS.md updates\n- After a PR merges to main — audit whether merged changes left AGENTS.md files outdated\n- On explicit request — \"are the AGENTS.md files up to date?\"\n\n## Workflow\n\n### 1. Determine the diff\n\nFigure out what changed relative to the base branch. The approach depends on context:\n\n- **On a feature branch (pre-PR):** diff against main\n  ```bash\n  git diff main...HEAD --name-status\n  git diff main...HEAD\n  ```\n- **After a merge to main:** the user should specify which PR or commit range to audit. Use the merge commit or PR number to get the diff:\n  ```bash\n  gh pr diff <number>\n  ```\n- **Explicit check:** if the user just says \"check AGENTS.md\", diff against main\n\n### 2. Map changes to AGENTS.md territories\n\nEach AGENTS.md file \"owns\" the directory it lives in and all subdirectories (unless a child directory has its own AGENTS.md). Build a list of which AGENTS.md files are relevant by walking up from each changed file to find the nearest AGENTS.md.\n\nExample: a change to `src/prefect/server/api/flows.py` is owned by `src/prefect/server/AGENTS.md` (if it exists), otherwise `src/prefect/AGENTS.md`.\n\nOnly analyze AGENTS.md files that have at least one changed file in their territory. Also include parent AGENTS.md files if structural changes (new directories, moved files) affect the directory tree they document.\n\n### 3. Check for missing AGENTS.md files\n\nBefore analyzing existing AGENTS.md files, check whether any changed directories *should* have their own AGENTS.md but don't. New AGENTS.md files should be rare. Recommend one only when the directory has both:\n\n- A real ownership boundary that a future agent needs to recognize before editing\n- Hidden conventions, non-obvious contracts, or recurring pitfalls that cannot be learned quickly from reading the code\n\nLook at the directories containing changed files. For each one that lacks an AGENTS.md, check:\n1. **Ownership boundary**: Does this directory represent a responsibility shift with different contracts than its parent?\n2. **Hidden knowledge**: Are there non-obvious patterns, invariants, conventions, or failure modes that a developer would not learn quickly from code?\n3. **Durability**: Will this guidance still matter after the triggering PR is old news?\n4. **Hierarchy fit**: Would this belong better in an existing parent AGENTS.md instead?\n\nDirectory size and sibling AGENTS.md files can be weak signals, but they are never sufficient on their own. Do not recommend a new AGENTS.md just because a directory has 5+ files, gained a new module, or has sibling directories with AGENTS.md files.\n\nWhen the case is not high-confidence, do not create the file. Capture the possible update as a recommendation instead, with the missing evidence or question that would make it actionable.\n\nWhen recommending a new AGENTS.md, use the Explore agent to read the directory's code and draft the file using this template:\n\n```markdown\n# <Module Name>\n\n<One-sentence purpose statement.>\n\n## Purpose & Scope\n\nWhat this module does. Explicit responsibility boundaries.\nWhat it does NOT do (prevents scope creep).\n\n## Entry Points & Contracts\n\nKey APIs, functions, classes that external consumers use.\nInput/output contracts. Invariants that must hold.\n\n## Usage Patterns\n\nCanonical examples of correct usage.\n\"If you need to do X, here's how.\"\n\n## Anti-Patterns\n\nWhat NOT to do. Common mistakes. Each should be a real mistake, not hypothetical.\n\n## Pitfalls\n\nNon-obvious gotchas. Implicit assumptions.\n\"You'd think X, but actually Y because Z.\"\n```\n\nThe initial content must be concise and durable. Do not include `[ASK]` placeholders, file lists, changelog context, or speculative guidance. If the hidden knowledge cannot be stated confidently, write a recommendation instead of creating the file.\n\n### 4. Analyze each relevant AGENTS.md\n\nAGENTS.md files form a hierarchy — when an agent loads any file, all ancestor files load too, creating a T-shaped view (broad context at the top, specific detail where the agent works). This has two implications for the sync check:\n\n**Least common ancestor rule**: Shared knowledge should live at the shallowest AGENTS.md that covers all paths needing it. If the same fact appears in multiple sibling AGENTS.md files, flag it — it should move to their parent. Conversely, if a parent AGENTS.md contains detail that only applies to one child directory, suggest moving it down.\n\n**Upward propagation**: When a child AGENTS.md changes (or a new one is created), check whether the parent needs updating — either to add a cross-reference to the new child, or to re-summarize what the child directory does. Parent nodes should summarize their children's responsibilities, not duplicate their details.\n\nFor each AGENTS.md in scope, read it fully, then compare its claims against the diff **and** the current source code. Look for these categories of issues:\n\n**Accuracy** — claims in AGENTS.md that don't match the actual code, regardless of whether the diff caused the discrepancy:\n- Described behaviors that don't match what the code actually does (e.g., \"renews at 75% of duration\" when it actually renews immediately then sleeps 75%)\n- Function signatures or parameters listed that are wrong or incomplete\n- Responsibilities attributed to the wrong layer or module\n- Error handling or failure modes described incorrectly\n\nFor claims that are verifiable (specific behaviors, function signatures, which module does what), read the source file and confirm. Don't trust that existing AGENTS.md content was ever correct — it may have been wrong from the start.\n\n**Signal density** — content that duplicates what's discoverable from code rather than surfacing hidden knowledge:\n- Full function signatures that just repeat the code (the *contracts* and *gotchas* around those functions are the high-signal parts)\n- Trivial usage examples that match what's in docstrings or is obvious from the API\n- File-by-file directory listings that `ls` would show — the *layering concept* or *architectural invariant* matters, not the enumeration\n- Content that a developer would learn in 30 seconds of reading the source\n\nAGENTS.md should capture what's *not* visible in the code: invariants, hidden contracts, non-obvious failure modes, things that look one way but behave another.\n\nA behavior discovered in one changed function is not AGENTS-worthy by default.\nPromote it only if it exposes a subsystem-level editing rule, a cross-file\ncontract, or a recurring failure mode future agents need before choosing\nwhich implementation to read. Otherwise prefer a code comment, docstring,\ntest name, or no documentation change.\n\nIf the same guidance is already present in nearby code comments, docstrings, or tests, AGENTS.md should usually not repeat it.\n\n**Missing invariants** — implicit contracts the code relies on that aren't documented:\n- Parallel implementations that must stay in sync (e.g., sync and async versions of the same module)\n- Ordering requirements or sequencing constraints\n- Singleton behaviors or shared mutable state\n- Cleanup responsibilities and what happens when they're skipped\n- \"This looks stateless but actually depends on X\"\n\n**Structural drift** — the AGENTS.md describes an ownership boundary, durable package layout, or module responsibility that no longer matches reality:\n- Directories or packages added/removed/renamed in a way that changes responsibility boundaries\n- New architectural layers or cross-file contracts not mentioned\n- Removed components still listed as active responsibilities\n\n**Command drift** — documented commands that may no longer work or are incomplete:\n- Build/test/run commands referencing changed entry points\n- New tooling or scripts not mentioned\n\n**Convention drift** — code patterns or conventions described in AGENTS.md that the diff contradicts:\n- New patterns established by the changes that aren't documented\n- Existing conventions the changes deprecate or replace\n\n**Description drift** — prose descriptions that no longer accurately characterize the code:\n- Component descriptions that miss new responsibilities\n- Architecture notes that don't reflect refactoring\n\n**Hierarchy drift** — content living at the wrong level in the AGENTS.md tree:\n- Knowledge duplicated across sibling AGENTS.md files that should be in their parent (least common ancestor)\n- Parent-level detail that only applies to one child directory\n- Parent summaries of child directories that no longer match after changes\n\nFor each finding, check whether it's actually stale — read the current state of the filesystem (not just the diff) to confirm. A diff showing a new file, helper, flag, or one-off fix doesn't mean AGENTS.md is wrong if AGENTS.md intentionally omits that level of detail.\n\nOnly recommend or apply updates for high-confidence, lasting guidance:\n- Architectural boundaries\n- Non-obvious invariants\n- Cross-file contracts\n- Recurring failure modes\n- Commands or conventions that future agents are likely to need\n\nDo not document:\n- One-off implementation details or temporary bug context\n- Facts obvious from reading names, imports, or nearby code\n- File lists or every new module\n- Changelog-style summaries of the triggering diff\n- Advice that only matters for the current PR\n\n### 5. Produce the report\n\nOutput a concise report grouped by AGENTS.md file. For each file, list findings with:\n- **What's stale** — the specific line or section\n- **Why** — which change caused it\n- **Suggested fix** — the concrete text to add, remove, or change\n\nFormat:\n\n```markdown\n## AGENTS.md Sync Report\n\n### New AGENTS.md recommended: `src/prefect/utilities/`\n\nThis directory now owns a distinct retry protocol used by multiple callers, and contributors must preserve its ordering invariant. Suggested outline:\n- Purpose and ownership boundary\n- Ordering invariant that callers rely on\n- Failure mode to test when changing it\n\n### `src/prefect/server/AGENTS.md`\n\n1. **[Accuracy]** Lease renewal described as \"renews at 75% of duration\" but code renews immediately then sleeps 75%\n   - Caused by: incorrect from initial creation\n   - Suggested fix: \"renews immediately on entry, then sleeps for 75% of `lease_duration` between renewals\"\n\n2. **[Signal density]** Full function signatures duplicate the code — remove parameter lists, keep contracts\n   - Suggested fix: Replace `concurrency(names, occupy=1, ...)` with `concurrency()` and describe the non-obvious behaviors instead\n\n3. **[Missing invariant]** Sync and async implementations must stay in lockstep but this isn't documented\n   - Suggested fix: Add \"Any behavior change to `_asyncio.py` must be mirrored in `_sync.py`\"\n\n4. **[Structural]** New directory `src/prefect/server/events/` not listed in directory structure\n   - Caused by: `src/prefect/server/events/` added in this branch\n   - Suggested fix: Add `events/` to the directory listing with description\n\n### `./AGENTS.md` (root)\nNo changes needed.\n```\n\nIf nothing is stale, say so clearly — don't manufacture findings.\n\n### 6. Offer next steps\n\nAfter presenting the report, offer:\n- **Apply fixes** — make the suggested edits directly\n- **Create a follow-up PR** — if this is a post-merge audit, offer to create a branch and PR with just the AGENTS.md updates\n- **Skip** — if the changes are minor or the user disagrees with the suggestions\n\n## Reactive mode\n\nOutside of diff-driven analysis, if during normal development you discover missing context that should be in an AGENTS.md, propose an addition. Signs of missing context:\n\n- You spent nontrivial time reconstructing a durable invariant that could be a one-liner in AGENTS.md\n- You hit a non-obvious error because of an undocumented constraint\n- You discovered a cross-system dependency that isn't mentioned anywhere\n- A code review caught something that AGENTS.md should have prevented\n\nPropose additions like this:\n```\nI discovered that [finding]. This isn't in [path]/AGENTS.md.\n\nProposed addition to the [section] section:\n> [concrete text to add]\n\nShould I add this?\n```\n\n## Quality checks for new or updated AGENTS.md content\n\n- **Compression**: Can any section be shorter without losing information?\n- **Deduplication**: Does anything repeat what a parent AGENTS.md already says? If so, remove it and rely on the hierarchy.\n- **Specificity**: Replace vague statements with concrete ones. Not \"be careful with auth\" but \"place logic after the `require_*` call\".\n- **Target length**: 20-80 lines for new files. If longer, compress or write recommendations instead.\n\n## Important guidelines\n\n- Be conservative — only flag things that are genuinely wrong or missing. AGENTS.md files are intentionally concise and don't need to document every file.\n- Don't suggest adding content that's obvious from the code itself. AGENTS.md captures non-obvious patterns, gotchas, and high-level structure. Equally, flag *existing* content that merely restates the code — full function signatures, trivial examples, and file enumerations are low-signal and should be trimmed or replaced with the hidden knowledge around them.\n- Don't trust that existing AGENTS.md content was ever correct. Verify factual claims (behaviors, signatures, responsibility attribution) against the source code, not just against the diff. Content can be wrong from day one.\n- Don't suggest stylistic rewrites. Focus on factual accuracy and signal density.\n- When in doubt about whether something is stale, check the filesystem to confirm rather than guessing from the diff alone.\n- Respect the existing level of detail in each AGENTS.md. If a file only lists top-level directories, don't suggest adding individual files.\n- Look for undocumented invariants — parallel implementations that must stay in sync, ordering constraints, singleton behaviors, cleanup responsibilities. These are the highest-value additions because they're invisible in code and cause the most breakage when violated.\n","frontmatter":{"name":"agents-md-sync","description":"Analyze code changes on the current branch and recommend updates to AGENTS.md files that have become stale. Use this skill before creating a PR, when the user asks to check AGENTS.md freshness, or when preparing an AGENTS.md update after a PR merges to main. Trigger whenever the user mentions syncing, updating, or checking AGENTS.md files, or when they're about to create a PR that touches code structure (new modules, renamed directories, changed commands, modified architecture)."},"isInternal":false,"tokens":3123,"sizeBytes":14768},{"name":"SKILL.md","path":".claude/skills/backlog-management/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/.claude/skills/backlog-management/SKILL.md","title":"backlog-management","category":"anthropic-skill","format":"markdown","content":"---\nname: backlog-management\ndescription: Manage open-source GitHub issue backlogs (especially PrefectHQ/prefect) in batches. Use for backlog cleanup days, stale review, duplicate pruning, missing-info follow-up, and prioritized queue curation across many open issues.\n---\n\n# Backlog Management\n\nUse this skill for batch backlog work, not for deep triage of a single new issue.\n\n## Scope\n\n- Open-source repositories only.\n- Use public, contributor-friendly language.\n- Do not reference internal plans or private project context.\n\n## Default Mode\n\n- Work in batches of 25-100 issues.\n- Start in read-only mode and propose actions first.\n- Apply edits only after approval unless explicitly asked to execute immediately.\n\n## Workflow\n\n1. Build a candidate batch.\n2. Assign one primary action per issue.\n3. Deep-dive only close candidates.\n4. Draft concise comments where needed.\n5. Apply approved edits.\n6. Report outcomes with counts and issue links.\n\n## Two-Pass Review Depth\n\nUse two passes by default:\n\n- Pass 1 (sweep): classify quickly across the full batch.\n- Pass 2 (dig-in): re-review only `close-not-planned` and `close-duplicate` candidates.\n\nDo not finalize close actions from Pass 1 alone.\n\nFor Pass 2, require explicit evidence:\n\n- architecture/status check against current Prefect behavior\n- concrete links (issue comments, PRs, release notes, docs, code)\n- counterevidence (why issue might still be valid)\n- confidence (`low`, `medium`, `high`)\n\nIf evidence is weak or mixed, downgrade close to:\n\n- `needs:details`\n- `needs:mre`\n- `status:stale`\n- `keep-open`\n\nUI replatform exception:\n\n- Prefect currently has both legacy UI code (`ui/`) and the React replatform (`ui-v2/`).\n- For UI issues that appear tied to legacy UI behavior, do not close based only on age/architecture drift until `ui-v2` is GA.\n- Before proposing close, check whether the reported behavior is represented in `ui/`, `ui-v2/`, or both.\n- Default action before GA is `keep-open` (or `status:stale` only if explicitly desired by maintainers).\n\n## Candidate Queries (PrefectHQ/prefect)\n\nUse focused searches:\n\n```bash\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue no:assignee sort:updated-asc\" --limit 100\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue label:status:stale sort:updated-asc\" --limit 100\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue label:bug -label:needs:mre sort:updated-asc\" --limit 100\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue label:needs:details sort:updated-asc\" --limit 100\n```\n\n## Action Set\n\nChoose exactly one primary action per issue:\n\n- `keep-open`: still actionable, no immediate label change needed\n- `needs:details`: missing context blocks progress\n- `needs:mre`: bug report lacks minimal reproducible example\n- `status:stale`: inactive and low-signal, not exempt\n- `close-duplicate`: close with canonical issue link\n- `close-not-planned`: close with concise reason when clearly out of scope or no longer actionable\n\n## Deep-Dive Output Format\n\nFor every close candidate, produce this mini-record before execution:\n\n- `issue`: number + title\n- `claim_to_verify`: why it appears closable\n- `current_state_check`: does claim still hold today?\n- `evidence_links`: specific references\n- `counterevidence`: any signal to keep open\n- `recommended_action`: final action after deep-dive\n- `confidence`: low/medium/high\n\n## Real Labels (PrefectHQ/prefect)\n\nOnly use labels that exist in this repo. Key labels for backlog work include:\n\n- `needs:details`\n- `needs:mre`\n- `status:stale`\n- `needs:triage`\n- `question`\n- `bug`\n- `enhancement`\n- `good first issue`\n- `blocked`\n- `status:exempt`\n\nVerify labels before applying changes:\n\n```bash\ngh label list --repo PrefectHQ/prefect --limit 30\n```\n\n## Comment Templates\n\nMissing details:\n\n```text\nThanks for opening this. We need a bit more detail before we can move this forward:\n- expected behavior\n- actual behavior\n- exact steps to reproduce\n```\n\nMissing MRE:\n\n```text\nThanks for the report. Please share:\n1) a minimal reproducible code sample,\n2) full traceback/error text,\n3) output of `prefect version`.\n```\n\nDuplicate close:\n\n```text\nClosing as a duplicate of #<issue-number> so discussion stays in one place.\nIf this is materially different, tag me and comment with details; we can reopen.\n```\n\n## Guardrails\n\n- Do not close issues only because they are old.\n- Do not mark as stale when clear maintainer/reporter activity is recent.\n- Do not apply conflicting labels.\n- Do not over-explain; keep comments short and specific.\n- Do not close legacy-UI issues before `ui-v2` GA unless there is a strong non-UI reason (for example, duplicate with active canonical issue).\n","frontmatter":{"name":"backlog-management","description":"Manage open-source GitHub issue backlogs (especially PrefectHQ/prefect) in batches. Use for backlog cleanup days, stale review, duplicate pruning, missing-info follow-up, and prioritized queue curation across many open issues."},"isInternal":false,"tokens":1155,"sizeBytes":4710},{"name":"SKILL.md","path":".claude/skills/document-changes/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/.claude/skills/document-changes/SKILL.md","title":"document-changes","category":"anthropic-skill","format":"markdown","content":"---\nname: document-changes\ndescription: Analyze source code changes on the current branch and identify documentation that is stale, inaccurate, or missing. Use before creating a PR to check if docs need updating, or in CI after merges to main to automatically fix docs. Trigger when the user mentions \"doc changes\", \"docs update\", \"check docs\", \"document changes\", or wants to know if code changes affect documentation.\n---\n\n# Document Changes\n\nAnalyze source code changes to find documentation that is stale, inaccurate, or missing, then either report findings or directly apply fixes.\n\n## Modes\n\n- **Report mode (default, local dev):** Produce a structured report of findings with suggested fixes. Offer to apply them.\n- **Edit mode (CI):** Directly apply fixes to existing doc pages. Do not create entirely new pages — flag those as recommendations in the PR body instead.\n\nThe mode is determined by how the skill is invoked. Local interactive use defaults to report mode. CI sets edit mode via the prompt.\n\n## Prerequisites\n\nBefore making any doc edits, read the write-docs skill at `.claude/skills/write-docs/SKILL.md`. All edits must follow its conventions for tone, components, frontmatter, code blocks, and testing directives.\n\n## Workflow\n\n### 1. Determine the diff\n\nFigure out what changed relative to the base branch:\n\n- **On a feature branch (pre-PR):** diff against main\n  ```bash\n  git diff main...HEAD --name-status\n  git diff main...HEAD -- 'src/prefect/' 'src/integrations/'\n  ```\n- **After a merge to main (CI):** read the diff provided at `/tmp/diff.patch`\n- **Explicit check:** diff against main\n\nFilter the diff to only source code changes. Skip:\n- Test files (`**/tests/**`)\n- CI/workflow files (`.github/`)\n- Documentation files (`docs/`, `*.md`, `*.mdx`)\n- Lock files (`uv.lock`, `package-lock.json`)\n- UI files (`ui-v2/`)\n\n### 2. Extract public API surface changes\n\nScan the diff for changes that users would encounter:\n\n**Function and class signatures:**\n- New, renamed, or removed public functions/classes/methods\n- Changed parameters (added, removed, renamed, retyped)\n- Changed default values\n- Changed return types\n\n**CLI commands:**\n- New, renamed, or removed commands (look for `@app.command()`, click/typer decorators)\n- Changed arguments or options\n- Changed help text\n\n**Configuration and settings:**\n- New, renamed, or removed settings (look for `Setting`, `Field` in settings classes)\n- Changed defaults or validation\n- Changed environment variable names\n\n**Behavioral changes:**\n- Changed error types or messages users would see\n- Changed lifecycle behavior (e.g., retry logic, state transitions)\n- Changed defaults that affect runtime behavior\n\n**Skip:**\n- Private/internal symbols (names starting with `_` in `_internal` modules)\n- Type-only changes that don't affect runtime behavior\n- Import reorganizations that don't change the public API\n- Pure refactors with no behavioral change\n\n### 3. Map changes to existing docs\n\nFor each extracted change, search the docs for references. Use parallel searches for efficiency.\n\n**Exclude auto-generated files.** Before searching or editing, filter out all auto-generated doc files. These are maintained by generation scripts and will be updated separately before each release. Never search, flag, or edit these paths:\n- `docs/v3/api-ref/` — entire directory (generated by `scripts/generate_api_ref.py` and `scripts/generate_settings_ref.py`)\n- `docs/v3/examples/` — entire directory (generated by `scripts/generate_example_pages.py`)\n- Any file containing a comment like `This page is generated by` or `automatically generated`\n\n**Search strategy:**\n- Grep `docs/` (excluding auto-generated paths above) for function names, class names, CLI command names, setting names\n- Check concept pages that explain the changed feature's behavior\n- Check how-to guides that demonstrate the changed API\n- Check get-started pages if fundamental APIs changed\n- Check integration docs if integration entry points changed\n\n**Build a findings list with these categories:**\n\n**Stale — docs describe something that changed:**\n- Wrong default value documented\n- Old parameter name or signature\n- Removed feature still documented\n- Behavior description that no longer matches the code\n- Code examples using old API\n\n**Missing — new public API/feature with no doc coverage:**\n- New public function/class with no mention in any doc page\n- New CLI command not documented\n- New setting not listed in configuration docs\n- New feature that extends an existing documented concept\n\n**Broken examples — code blocks that reference changed APIs:**\n- Code blocks using removed or renamed functions\n- Code blocks with old parameter names\n- Code blocks that would produce different output than described\n\n### 4. Produce output\n\n#### Report mode (local dev)\n\nPrint a structured report grouped by doc file:\n\n```markdown\n## Documentation Changes Report\n\n### `docs/v3/concepts/flows.mdx`\n\n1. **[Stale]** Line 45: `@flow(retries=3)` — `retries` parameter renamed to `max_retries` in src/prefect/flows.py\n   - **Suggested fix:** Update parameter name in code example and surrounding prose\n\n2. **[Broken example]** Line 78-85: Code block uses `flow.run()` which was removed\n   - **Suggested fix:** Replace with `flow()` direct invocation\n\n### `docs/v3/how-to-guides/workflows/retries.mdx`\n\n1. **[Stale]** Line 23: \"Default retry delay is 5 seconds\" — default changed to 10 seconds in this branch\n   - **Suggested fix:** Update to \"Default retry delay is 10 seconds\"\n\n### Missing coverage\n\n1. **[Missing]** New `@flow(on_cancellation=...)` hook added — no docs mention this parameter\n   - **Recommendation:** Add a section to `docs/v3/concepts/flows.mdx` under \"Flow lifecycle hooks\" or create a new how-to guide\n\n### No changes needed\n- `docs/v3/get-started/quickstart.mdx` — references checked, all current\n```\n\nAfter presenting the report, offer:\n- **Apply fixes** — make the suggested edits to existing pages (follow write-docs skill conventions)\n- **Skip** — if the user disagrees with findings or wants to handle manually\n\n#### Edit mode (CI)\n\nDirectly apply fixes for **Stale** and **Broken example** findings on existing pages:\n- Skip any file under an auto-generated path (`docs/v3/api-ref/`, `docs/v3/examples/`) or containing a generated-by comment — do not edit these even if they appear stale\n- Read each affected doc file\n- Make targeted, minimal edits to fix the specific issues\n- Do not rewrite surrounding content\n- Do not change tone, style, or structure beyond what's needed\n- For code blocks, ensure the fix is syntactically valid\n- Add `{/* pmd-metadata: notest */}` only if the fixed code genuinely can't be tested\n\nFor **Missing** coverage findings, do not create new pages. Instead, collect them for the PR body.\n\n### 5. Quality gate (edit mode only)\n\nBefore considering edits complete, verify each change:\n- Follows write-docs tone (second person, active voice, no marketing language)\n- Uses Mintlify components correctly (not markdown admonitions)\n- Preserves existing frontmatter (title, description, keywords)\n- Does not add or remove pages from `docs/docs.json`\n- Code blocks are syntactically valid Python/bash\n- Changes are minimal — only what's needed to fix the finding\n\n### 6. Offer next steps (report mode only)\n\nAfter applying fixes (if the user chose to), mention:\n- Run `just lint` in `docs/` to check Vale style\n- Run markdown tests if code blocks were modified\n- Any missing coverage items that need new content written (suggest using the write-docs skill)\n\n## Important guidelines\n\n- **Be conservative.** Only flag things that are genuinely wrong or missing. A doc page that doesn't mention every parameter is fine — it's stale only if it mentions the *wrong* value or a *removed* thing.\n- **Don't rewrite for style.** If the prose is accurate, leave it alone even if you'd write it differently.\n- **Verify before flagging.** Read both the diff and the current doc file. A grep hit doesn't mean the doc is wrong — read the context.\n- **Respect doc scope.** Not every public API needs docs. Flag missing coverage for features users would reasonably expect to find documented, not for every internal helper that happens to be public.\n- **Minimize blast radius in CI.** Small, targeted fixes only. If a finding requires judgment about page structure or new content, leave it as a recommendation rather than an automated edit.\n- **Don't touch auto-generated pages.** Skip the entire `docs/v3/api-ref/` directory (including `settings-ref.mdx`, Python SDK reference, CLI reference, and REST API reference), the entire `docs/v3/examples/` directory, and any file containing a generated-by comment (e.g., `This page is generated by`). These files are regenerated by scripts before each release and must not be edited manually or by automation.\n- **Check code block test directives.** If you modify a code block, check whether it has `pmd-metadata` directives and preserve them. If you're unsure whether a modified block is testable, mark it `notest` and note why.\n","frontmatter":{"name":"document-changes","description":"Analyze source code changes on the current branch and identify documentation that is stale, inaccurate, or missing. Use before creating a PR to check if docs need updating, or in CI after merges to main to automatically fix docs. Trigger when the user mentions \"doc changes\", \"docs update\", \"check docs\", \"document changes\", or wants to know if code changes affect documentation."},"isInternal":false,"tokens":2041,"sizeBytes":9070},{"name":"SKILL.md","path":".claude/skills/write-docs/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/.claude/skills/write-docs/SKILL.md","title":"write-docs","category":"anthropic-skill","format":"markdown","content":"---\nname: write-docs\ndescription: Comprehensive guide for writing and updating Prefect documentation. Use when creating new doc pages, updating existing docs, or working with Mintlify components and code example testing.\n---\n\n# Writing Prefect Documentation\n\nThis guide covers everything needed to write, update, and test Prefect documentation pages. For structural context (directory layout, navigation, links, local dev commands), see `docs/AGENTS.md`.\n\n## Page types\n\nEach section of the docs serves a distinct purpose. Place new content in the right section and match its tone and structure.\n\n### Get Started (`v3/get-started/`)\n\nOnboarding pages for new users. Content should be linear, opinionated, and get the reader to a working result as fast as possible. Use `<Steps>` for sequential instructions and `<Tabs>` to offer Cloud vs. self-hosted paths. Minimize explanation — link to Concepts for deeper understanding.\n\n### Concepts (`v3/concepts/`)\n\nExplain **what** something is and **why** it matters. Concepts pages define Prefect's mental model — flows, tasks, states, deployments, events, work pools, etc. Start with a short code example showing the concept in action, then explain the underlying model, lifecycle, and relationships to other concepts. Link to How-to Guides for step-by-step instructions. Do not provide exhaustive procedural walkthroughs here.\n\n### How-to Guides (`v3/how-to-guides/`)\n\nTask-oriented pages that show **how** to accomplish a specific goal. Each page should solve one problem (e.g., \"How to write and run a workflow\", \"How to set up retries\"). Structure as a series of actionable steps with code examples. Meet the reader where they are — do not assume familiarity with Prefect internals. Use the smallest amount of Prefect-specific jargon possible, and explain or link terms when they are unavoidable.\n\nGuides are organized into the following categories:\n\n- **`workflows/`** — Writing, running, and customizing flows and tasks: retries, caching, concurrency, logging, testing, runtime info, state hooks, and artifacts.\n- **`deployments/`** — Creating, scheduling, running, and versioning deployments, including `prefect.yaml` configuration and flow code storage.\n- **`deployment_infra/`** — Running workflows on specific infrastructure: Docker, Kubernetes, serverless platforms (AWS ECS, Azure ACI, GCP Cloud Run), Modal, Coiled, Prefect Managed, and local processes. Also covers work pool management.\n- **`automations/`** — Setting up event-driven automations: creating automations and triggers, chaining deployments via events, custom notifications, and accessing event payloads in flows.\n- **`cloud/`** — Prefect Cloud-specific operations: connecting to Cloud, managing workspaces and users, creating webhooks, and troubleshooting.\n- **`configuration/`** — Configuring the Prefect environment: managing settings, storing secrets, and using variables.\n- **`ai/`** — Using Prefect with AI tooling, such as the Prefect MCP server.\n- **`migrate/`** — Upgrading from older Prefect versions or migrating from other tools like Airflow.\n- **`self-hosted/`** — Running the Prefect server yourself via Docker Compose, the CLI, or on Windows.\n\n### Advanced (`v3/advanced/`)\n\nIn-depth pages for experienced users covering topics like transactions, interactive workflows, infrastructure-as-code, scaling self-hosted deployments, and custom API integrations. These assume familiarity with core concepts and how-to patterns. They can be longer and more detailed than how-to guides.\n\n### Examples (`v3/examples/`)\n\n**Auto-generated — do not edit directly.** Each page is generated from a standalone Python file in the repo's top-level `examples/` directory by `generate_example_pages.py`. To add an example, create a new `.py` file in `examples/` with YAML frontmatter in comments and run `just generate-examples`. See `contribute/docs-contribute.mdx` for the full process.\n\n### Integrations (`integrations/`)\n\nEach integration (e.g., `prefect-aws`, `prefect-gcp`) has its own subdirectory. The `index.mdx` covers installation, credential setup (blocks), and key capabilities. Additional pages cover specific workers, tasks, or SDK reference. Follow the existing pattern: \"Why use it\" section, prerequisites, install instructions, blocks setup, then per-service usage sections.\n\n### API Reference (`v3/api-ref/`)\n\n**Auto-generated — do not edit directly.** Covers the Python SDK (`python/`), CLI commands (`cli/`), and REST API (`rest-api/`). CLI pages use `<ResponseField>` and `<Accordion>` components for arguments and options.\n\n### Release Notes (`v3/release-notes/`)\n\nChangelogs organized by product surface: `oss/` for open-source releases, `cloud/` for Prefect Cloud, `integrations/` for integration packages.\n\n### Contribute (`contribute/`)\n\nGuides for contributors: how to set up the dev environment, write docs, develop integrations, and follow code style conventions.\n\n## Adding vs. updating content\n\n### When to update an existing page vs. create a new one\n\n- **Update an existing page** when the new content is a variation, option, or closely related technique for something the page already covers. For example, a new retry strategy belongs on the existing retries page, not a new page.\n- **Create a new page** when the content addresses a distinct goal that doesn't fit naturally into any existing page. A good test: if the page title would need to become vague or a compound sentence to accommodate the new content, it deserves its own page.\n- When in doubt, prefer extending an existing page. Fewer, more comprehensive pages are easier for readers to discover than many small, fragmented ones.\n\n### When to add a new category or section\n\n- **Create a new subdirectory** only when you have multiple pages (or a clear roadmap for multiple pages) that share a theme not covered by any existing category. A single page does not justify a new category — place it in the closest existing one.\n- Before creating a category, check whether the content fits in an existing one. For example, a guide about running flows on a new cloud platform belongs in `deployment_infra/`, not a new category named after that platform.\n- New categories must also be added as a group in the `navigation.tabs` section of `docs/docs.json`, with an `index.mdx` page for the group overview.\n\n## Page templates\n\nStarter templates live in this skill directory. Copy one as the basis for a new page and fill in the bracketed placeholders:\n\n- **How-to guide** — `template-howto.mdx`\n- **Concept page** — `template-concept.mdx`\n\nAdjust headings and sections to fit the content — the templates show the expected shape, not a rigid format.\n\n### Keywords for searchability\n\nEvery page should include a `keywords` array in its frontmatter. Keywords feed Mintlify's search index and help readers find pages using terms that don't appear in the title or description.\n\n```yaml\nkeywords: [\"retry\", \"retries\", \"error handling\", \"fault tolerance\"]\n```\n\n- Include 3-5 lowercase terms a reader might search for.\n- Use synonyms and shorthand readers would actually type (e.g., \"k8s\" is wrong in prose but useful as a keyword alongside \"Kubernetes\").\n- Don't repeat words already in `title` or `description` — those are indexed automatically.\n\n## Registering pages in navigation\n\nEvery new page must be added to `docs/docs.json` under `navigation.tabs` or it won't appear in the sidebar. Add the page path (without `.mdx`) to the appropriate group:\n\n```json\n{\n  \"tab\": \"How-to Guides\",\n  \"pages\": [\n    \"v3/how-to-guides/index\",\n    {\n      \"group\": \"Workflows\",\n      \"pages\": [\n        \"v3/how-to-guides/workflows/write-and-run\",\n        \"v3/how-to-guides/workflows/retries\"\n      ]\n    }\n  ]\n}\n```\n\n- Each tab has a `\"tab\"` display name and either `\"pages\"` or `\"groups\"`.\n- Groups can nest: a group's `\"pages\"` array can contain strings (page paths) or nested `{\"group\": ..., \"pages\": [...]}` objects.\n- Place new pages at a logical position within the existing group — typically at the end, unless ordering matters for the reader.\n\n## Mintlify components\n\nUse these components (not standard Markdown admonition syntax):\n\n```mdx\n<Note>Important information.</Note>\n<Warning>Caution about potential issues.</Warning>\n<Tip>Helpful suggestion.</Tip>\n<Info>Additional context.</Info>\n\n<Accordion title=\"Expandable section\">\n  Content hidden until clicked.\n</Accordion>\n\n<Tabs>\n  <Tab title=\"Option A\">Content for A</Tab>\n  <Tab title=\"Option B\">Content for B</Tab>\n</Tabs>\n\n<Steps>\n  <Step title=\"First step\">Instructions</Step>\n  <Step title=\"Second step\">Instructions</Step>\n</Steps>\n\n<CardGroup cols={3}>\n  <Card title=\"Title\" icon=\"icon\" href=\"/v3/path\">\n    Description text.\n  </Card>\n</CardGroup>\n\n<CodeGroup>\n```bash pip\npip install prefect\n```\n```bash uv\nuv pip install prefect\n```\n</CodeGroup>\n```\n\n## Reusable snippets\n\nSnippets live in `snippets/` and are imported with JSX:\n\n```mdx\nimport ComponentName from '/snippets/path.mdx'\n\n<ComponentName />\n```\n\nAlways check for an existing snippet before writing duplicate content. Key snippets to know about:\n\n- `snippets/installation.mdx` — Standard Prefect install instructions (used in `v3/get-started/install.mdx`). Use this instead of writing ad-hoc install blocks.\n- `snippets/resource-management/` — Consistent \"manage this resource via CLI / API / Terraform / Helm\" callouts. Import the relevant variant when documenting a Prefect resource.\n\n## Code blocks\n\nCode blocks support language hints, filenames, line highlighting, and expandable sections:\n\n````mdx\n```python my_flow.py\nfrom prefect import flow\n\n@flow\ndef hello():\n    print(\"Hello!\")\n```\n\n```bash {3} [expandable]\nprefect deploy --all\nprefect work-pool create my-pool --type process\nprefect worker start --pool my-pool\n```\n````\n\nMark code blocks that should **not** be tested with the comment `{/* pmd-metadata: notest */}` on the line before the code block.\n\nPrefer minimal, runnable snippets that produce a visible result (printed output, a return value, or a logged message). Avoid placeholder names like `foo`/`bar` in user-facing examples — use realistic names that reflect the domain (e.g., `process_order`, `customer_id`).\n\n## Code example testing\n\nPython code blocks in `.mdx` files are automatically extracted and executed as tests using [pytest-markdown-docs](https://github.com/modal-labs/pytest-markdown-docs). Tests run in CI against a live Prefect server and are parallelized with pytest-xdist (up to 6 workers). All test configuration — fixtures, skip lists, and injected globals — lives in `docs/conftest.py`.\n\n### How it works\n\nBy default, every fenced Python code block in an `.mdx` file is treated as an independent test. The plugin extracts the block, executes it, and fails if it raises an exception. Each block runs in its own namespace unless `continuation` is used (see below).\n\n### Running tests locally\n\nThere is no `just` command for markdown tests. Run them manually:\n\n```bash\n# Start a Prefect server in the background\nPREFECT_HOME=$(pwd) uv run prefect server start &\n\n# Run the markdown doc tests\nPREFECT_API_URL=\"http://127.0.0.1:4200/api\" uv run --group markdown-docs pytest docs/ -m markdown-docs\n```\n\n### pmd-metadata directives\n\nControl test behavior with `{/* pmd-metadata: <directive> */}` comments placed on the line immediately before a code fence.\n\n**`notest`** — Skip this code block entirely. Use when code is illustrative, incomplete, or requires setup that cannot be provided in the test environment.\n\n```mdx\n{/* pmd-metadata: notest */}\n```python\n# This block will not be tested\nprefect deploy --some-hypothetical-flag\n```\n```\n\n**`continuation`** — Share state (imports, variables, function definitions) from preceding code blocks on the same page. Without this, each block starts with a clean namespace. Use when a multi-step example is split across blocks for readability.\n\n```mdx\n```python\nfrom prefect import flow\n\n@flow\ndef my_workflow() -> str:\n    return \"Hello, world!\"\n```\n\n{/* pmd-metadata: continuation */}\n```python\nmy_workflow()  # Can reference the function defined above\n```\n```\n\n**`fixture:<name>`** — Inject a pytest fixture defined in `conftest.py` as a global in the code block. Use when a block needs mocking (e.g., HTTP calls).\n\n```mdx\n{/* pmd-metadata: fixture:mock_post_200 */}\n```python\nimport requests\nresponse = requests.post(endpoint, headers=headers, json=data)\nassert response.status_code == 200\n```\n```\n\n### Global imports\n\nThe `pytest_markdown_docs_globals` hook in `conftest.py` injects a small set of globals into every code block automatically: `Mapped`, `Run`, `Union`, `mapped_column`, `sa`. You do not need to import these in doc examples.\n\n### Autouse fixtures\n\nTwo fixtures are applied to every test automatically (defined in `conftest.py`):\n\n- `mock_runner_start` — Mocks `prefect.cli.flow.Runner.start` so flow-serving examples don't actually start a long-running process.\n- `mock_base_worker_submit` — Mocks `BaseWorker.submit` and `KubernetesWorker.submit` so worker examples don't attempt real infrastructure calls.\n\n### Skipped files\n\nSome files are skipped entirely via the `SKIP_FILES` dict in `conftest.py`. Common reasons include needing database fixtures, block cleanup, live network calls, or async contexts. Additionally:\n\n- All files under `v3/api-ref/python/` are auto-skipped (generated reference docs).\n- All files under `v3/examples/` are auto-skipped (tested separately in their source repo).\n\nWhen adding a new page that genuinely cannot be tested, add it to `SKIP_FILES` with a reason rather than marking every block with `notest`.\n\n## Images\n\nPlace images in `v3/img/` organized by section (e.g., `v3/img/ui/`, `v3/img/concepts/`). Reference them with absolute paths:\n\n```mdx\n![Description](/v3/img/ui/screenshot.png)\n```\n\n- Always include meaningful alt text that describes what the image shows.\n- Use compressed PNG or WebP format to keep page load times fast.\n- Avoid committing unnecessarily large screenshots; crop to the relevant area.\n\n## Linting\n\nDocs are linted with [Vale](https://vale.sh/) using Google style, Vale defaults, and custom Prefect rules. Run locally:\n\n```bash\njust lint\n```\n\nOr manually: `vale --glob='**/*.{md,mdx}' .`\n\n## Tone and style\n\n- Use second person (\"you\") and active voice in present tense.\n- Avoid first person (\"I\", \"we\") and marketing language (\"powerful\", \"seamless\", \"best-in-class\").\n- Be direct and concise. Shorter sentences are easier to scan.\n- Follow the [Google developer documentation style guide](https://developers.google.com/style) as the baseline.\n\nExamples of preferred phrasing:\n\n| Instead of | Write |\n|---|---|\n| \"We recommend configuring...\" | \"Configure...\" |\n| \"You'll want to make sure to...\" | \"Make sure to...\" or just state the instruction |\n| \"This powerful feature allows you to...\" | \"Use [feature] to...\" |\n| \"I'll show you how to set up...\" | \"To set up..., do the following:\" |\n| \"It should be noted that...\" | State the fact directly |\n| \"In order to\" | \"To\" |\n\nWhen introducing a concept, lead with what the reader can *do*, not what the feature *is*:\n\n- Before: \"The retry mechanism is a configurable system that allows flows to recover from transient failures.\"\n- After: \"Add retries to your flow to recover automatically from transient failures.\"\n\n## Quality checklist\n\nBefore considering a page complete, verify:\n\n1. The page opens with appropriate context: for how-to guides, a single-sentence scope line (or jump straight into steps if the title already establishes the goal); for concepts and advanced pages, an opening paragraph that defines the topic and why it matters.\n2. Prerequisites (tools, access, prior knowledge) are called out up front.\n3. The page includes at least one cross-link to a related Concept or How-to page.\n4. All code blocks are runnable and tested, or explicitly marked with `{/* pmd-metadata: notest */}` with a reason.\n5. Frontmatter includes `keywords` with 3-5 search terms not already in the title or description.\n6. The page is registered in `docs/docs.json` navigation.\n\n## Common mistakes\n\n- Using `#` (H1) in the body — the frontmatter `title` already renders as H1.\n- Using relative links or including `.mdx` in link paths.\n- Using Markdown admonitions (`> **Note:**`) instead of Mintlify components (`<Note>`).\n- Inconsistent heading hierarchy (jumping from H2 to H4).\n- Missing `description` or `keywords` in frontmatter — both improve search discoverability.\n- First-person pronouns (\"I\", \"we\") — use \"you\" or imperative voice.\n- Wrong terminology casing: \"Prefect cloud\" (should be \"Prefect Cloud\"), \"Prefect Server\" (should be \"Prefect server\"), \"k8s\" (should be \"Kubernetes\"), \"infra\" (should be \"infrastructure\").\n- Forgetting to register a new page in `docs/docs.json` — the page won't appear in nav.\n- Forgetting to add a redirect in `docs/docs.json` when moving or renaming a page.\n- Overusing `<Note>`/`<Tip>`/`<Warning>` — reserve for genuinely important callouts, not every paragraph.\n","frontmatter":{"name":"write-docs","description":"Comprehensive guide for writing and updating Prefect documentation. Use when creating new doc pages, updating existing docs, or working with Mintlify components and code example testing."},"isInternal":false,"tokens":3936,"sizeBytes":17011},{"name":"template-concept.mdx","path":".claude/skills/write-docs/template-concept.mdx","rawUrl":"https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/.claude/skills/write-docs/template-concept.mdx","title":"Claude Directive: template-concept.mdx","category":"claude-rule","format":"markdown","content":"---\ntitle: [Concept name]\ndescription: [One sentence explaining what this concept does.]\nkeywords: [\"keyword1\", \"keyword2\", \"keyword3\"]\n---\n\n{/*\n  keywords: Include 3-5 lowercase terms a reader might search for.\n  Use synonyms and abbreviations readers would type — e.g., for a\n  flows page: [\"flow\", \"workflow\", \"orchestration\", \"decorator\"].\n  Don't repeat words already in the title or description.\n*/}\n\n```python\nfrom prefect import flow\n\n@flow\ndef my_flow():\n    return \"Hello!\"\n\nmy_flow()\n```\n\n## What is [concept]?\n\nExplain the concept and why it matters.\n\n## [Key aspect or behavior]\n\nDeeper explanation with examples.\n\n<Tip>\nCall out a key detail the reader should remember.\n</Tip>\n\n## Next steps\n\n- [How to do X with this concept](/v3/how-to-guides/category/guide)\n","frontmatter":{"title":["Concept name"],"description":["One sentence explaining what this concept does."],"keywords":["keyword1","keyword2","keyword3"]},"isInternal":false,"tokens":197,"sizeBytes":777},{"name":"template-howto.mdx","path":".claude/skills/write-docs/template-howto.mdx","rawUrl":"https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/.claude/skills/write-docs/template-howto.mdx","title":"Claude Directive: template-howto.mdx","category":"claude-rule","format":"markdown","content":"# Claude Directive: template-howto.mdx\n\nPath: `.claude/skills/write-docs/template-howto.mdx`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/.claude/skills/write-docs/template-howto.mdx)","tokens":300,"sizeBytes":225},{"name":"repro.md","path":".claude/commands/repro.md","rawUrl":"https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/.claude/commands/repro.md","title":"Command: /repro","category":"command-prompt","format":"markdown","content":"---\ndescription: Reproduce a bug in the Prefect codebase.\nargument-hint: \"[the gh issue link or issue number]\"\n---\n\nuse `gh` to read and understand the following github issue: $1.\n\nRead the body and all comments in the issue.\n\nbefore reproducing, `rg` for documentation in `docs/` that may be relevant to the issue.\n\nif a `repros/` directory already exists (it will be locally gitignored), `rg` for relevant SDK usage to gain context.\n\n\nTo reproduce, create a file named by issue number (ie. `1234.py`) in a locally gitignored (.git/info/exclude) `repros/` directory with a minimal reproducible example that reproduces the issue. Because `repros/` is gitignored, you should NEVER reference it in a PR body, instead put the entire reproduction script in a python snippet inside a `<details>` tag.\n\nIf the reproduction requires external dependencies, use `uv` to inline script dependencies to install them like this:\n\n```\n# ///script\n# dependencies = [\"pandas\", \"numpy\"]\n# ///\n\n# rest of script\n```\nand then invoke the script with `uv run --with-editable . repros/1234.py` to use the editable copy of Prefect along with the external dependencies.\n\nReview the actual `prefect` library in `src/prefect` (or integration in `src/integrations`) to ensure that the reproduction is aware of the implementation details of the code.\n","frontmatter":{"description":"Reproduce a bug in the Prefect codebase.","argument-hint":"[the gh issue link or issue number]"},"isInternal":false,"tokens":314,"sizeBytes":1322}],"systemPromptSnippet":"<yakaai_skills repo=\"PrefectHQ/prefect\">\n<!-- File: AGENTS.md (Tokens: ~2171 | Category: root-instruction) -->\nPrefect is a workflow orchestration platform that coordinates and observes data pipelines. It provides a Python SDK for building workflows, a server backend for orchestration, and a web-based UI for managing and monitoring workflows.\n\n# Guiding Principles\n\nYour primary responsibility is to the project and its users. Every change should serve the broader user base — not just the immediate request. Be a quality gate: prefer correct, minimal, well-tested changes over fast ones.\n\n# Before You Start\n\nBefore making code changes, read the public contribution guide in `docs/contribute/dev-contribute.mdx` so your work follows Prefect's contribution expectations, design principles, AI-use policy, testing standards, and maintainer review criteria.\nFor documentation-only changes, also read `docs/contribute/docs-contribute.mdx`.\nFor integration changes, also read `docs/contribute/contribute-integrations.mdx`.\n\n# Directory Structure\n\n```\nprefect/\n├── benches/                         # Benchmarks (CLI, flows, tasks, imports)\n├── client/                          # prefect-client build: subset of src/prefect/ published as a separate PyPI package\n├── compat-tests/                    # Tests for REST API compatibility with Prefect Cloud\n├── Dockerfile                       # Production container image\n├── docs/                            # Mintlify documentation (see docs/AGENTS.md)\n├── examples/                        # Example flows (auto-published to docs)\n├── formal/                          # Executable formal models (see formal/tla/AGENTS.md)\n├── integration-tests/               # End-to-end integration tests (require running server)\n├── justfile                         # Task runner (just <command>)\n├── load_testing/                    # Load/performance testing\n├── plans/                           # Design/implementation plan documents\n├── pyproject.toml                   # Root package config\n├── schemas/                         # JSON schemas (prefect.yaml, settings)\n├── scripts/                         # Code generation and release scripts\n├── src/\n│   ├── integrations/                # External service integrations (see src/integrations/AGENTS.md)\n│   └── prefect/                     # Core package: SDK, server, CLI (see src/prefect/AGENTS.md)\n├── tests/                           # Test suite, mirrors src/prefect/ (see tests/AGENTS.md)\n├── tools/                           # Build tools\n├── ui/                              # Vue UI (legacy, will be replaced by ui-v2)\n├── ui-v2/                           # React UI rewrite (see ui-v2/AGENTS.md)\n└── uv.lock                          # Lockfile (auto-generated, do not edit manually)\n```\n\n# Essential Commands\n\n```bash\n# Dependencies\nuv sync                                # Install all dev dependencies\njust install                           # Same as above, plus perf group\n\n# Running code\nuv run -s my_script.py                             # Run a script with an editable prefect install\nuv run --extra aws repros/1234.py                  # Run repro needing an integration extra\nuv run --project ./src/integrations/<name> <cmd>   # Run against a local integration from repo root\nprefect server start                               # Start local server\nprefect config view                                # Inspect current configuration\n\n# Testing (see tests/AGENTS.md for full details)\nuv run pytest tests/path.py -k name    # Run specific test\nuv run pytest tests/path.py -x -n4     # Parallel, stop on first failure\n\n# Linting & formatting\nuv run ruff check --fix .              # Lint with auto-fix\nuv run ruff format .                   # Format code\nuv run pre-commit run --all-files      # Run all pre-commit hooks\n\n# Docs (from repo root)\njust docs                              # Start Mintlify dev server at localhost:3000\njust generate-docs                     # Regenerate all doc artifacts\n\n# UI (from repo root)\njust ui-v2                             # Start React dev server at localhost:5173\n\n# Docker\ndocker build -t prefect .                              # Default build (Python 3.11)\ndocker build --build-arg PYTHON_VERSION=3.12 -t prefect .  # Custom Python version\ndocker build --build-arg EXTRA_PIP_PACKAGES=\"prefect-aws\" -t prefect .  # With extras\n```\n\n## Quick Reference\n\n| Component | Path | Tests |\n|-----------|------|-------|\n| Core SDK (flows, tasks, states, deployments) | `src/prefect/` | `tests/` |\n| Flow & task engines (async orchestration) | `src/prefect/flow_engine.py`, `task_engine.py` | `tests/engine/` |\n| Client SDK (schemas, HTTP client) | `src/prefect/client/` | `tests/client/` |\n| Server (API, database, scheduling) | `src/prefect/server/` | `tests/server/` |\n| CLI | `src/prefect/cli/` | `tests/cli/` |\n| Settings | `src/prefect/settings/` | `tests/settings/` |\n| Integrations (`prefect-aws`, `prefect-dbt`, etc.) | `src/integrations/` | per-integration |\n| React UI (replacing Vue `ui/`) | `ui-v2/` | `ui-v2/e2e/` |\n\n## Tech Stack & Tooling\n\n- **Python >=3.11,<3.16** with modern typing (`list[int]`, `T | None`)\n- **FastAPI** for REST APIs\n- **Pydantic v2** for validation\n- **SQLAlchemy 2.0** async ORM\n- **Alembic** for database migrations\n- **PostgreSQL/SQLite** databases\n- **React + TypeScript** for UI (see ui-v2/AGENTS.md)\n- **Ruff** for linting and formatting\n- **Pre-commit** hooks: ruff, codespell, mypy (partial), uv-lock, no-commit-to-branch\n\n## Architecture Overview\n\n- **Three user-facing surfaces**: Python SDK (`@flow`/`@task` decorators), CLI (`prefect` command), REST API (FastAPI server)\n- **Server is the source of truth for flow state transitions** — the flow engine proposes states, and the server's orchestration layer accepts or rejects them. Task state transitions are managed locally by the task engine via `set_state` and communicated through `prefect.task_run.*` events\n- **Two published packages**: `prefect` (full SDK + server) and `prefect-client` (lightweight client subset). `client/` contains the build config that selects which files from `src/prefect/` go into `prefect-client`\n- **Integrations are separate PyPI packages** (`prefect-aws`, `prefect-dbt`, etc.) each with their own version, published independently from `src/integrations/`\n- **Async-first execution model** with sync wrappers — the engines (`flow_engine.py`, `task_engine.py`) are async; sync `@flow`/`@task` functions are run in workers\n\n## Anti-patterns\n\n- **Never bypass the server for flow state transitions** — always go through the orchestration API, even in tests. Task state transitions are managed locally by the task engine by design\n- **Never use `pip install` or `uv pip`** — use `uv` for all dependency management\n- **Never use deferred imports** (imports inside functions) unless required to break circular imports or for optional dependencies\n- **Never commit directly to `main`** — a pre-commit hook enforces this\n- **Never skip pre-commit hooks** (`--no-verify`) — fix the underlying issue instead\n- **Never amend commits** (`--amend`) — create new commits instead\n\n# Development Guidelines\n\n## Make sure you have a Prefect server or Prefect Cloud\n- use `prefect config view` to check your current profile\n- run `prefect server start` in the background if needed\n\n## Code Conventions\n\n- Private implementation details (`_private_method`)\n- No public API changes without approval\n- Use single backticks for inline code references in docstrings, not double backticks\n\n## Testing\n\n- Directory structure mirrors source code\n- Run affected tests after changes: `uv run pytest tests/module/`\n- Tests require deterministic behavior\n- Mock external dependencies\n\n## Formal Protocol Models\n\n- Use TLA+ selectively for bounded concurrent or distributed protocols whose correctness depends on interleavings, retries, duplication, time, or ownership. Prefer ordinary tests for local or sequential behavior.\n- Treat each `formal/tla/<protocol>/README.md` as the authority for its scope, configurations, action-to-code mapping, owner, and review triggers.\n- Before changing mapped behavior, review the model and its deterministic regressions. Update them when the abstraction changes; otherwise state in the PR why it remains valid.\n- A green model validates only its documented abstraction, not Prefect's implementation. Implementation evidence comes from mapped behavior and contract tests.\n\n## Working on Issues\n\n- Read the GitHub issue/PR and comments (`gh issue view`, `gh pr view`) before writing code\n- Understand the scope and intended behavior — ask clarifying questions if unclear\n- Create reproduction scripts in `repros/` directory (create it if needed; add to `.gitignore`)\n- Name files by issue number: `repros/1234.py` (only create one file per issue)\n- Ensure the issue is reproducible before fixing\n- Add unit tests for fixes\n- DO NOT delete files from `repros/` directory after reproducing the issue unless asked\n\n## PR Body Style\n\n- Start with \"closes #1234\" if resolving issue\n- Brief summary: \"this PR {changes}\"\n- Details in `<details>` tag\n- Include relevant links\n\n## Code Review Rules\n\nWhen reviewing changes, read and apply [REVIEW.md](REVIEW.md).\n\n# Project Practices\n\n- All PRs require test coverage for new functionality\n- GitHub issues are used for tracking issues (use the `gh` cli)\n- Dependencies: updates to client-side deps in `pyproject.toml` require parallel changes in `client/pyproject.toml`\n- AGENTS.md always symlinked to CLAUDE.md\n\n<!-- File: client/AGENTS.md (Tokens: ~421 | Category: root-instruction) -->\n# prefect-client Package Build\n\nBuild configuration for `prefect-client`, a lightweight subset of `prefect` published as a separate PyPI package. This directory does **not** contain source code — it selects files from `src/prefect/` and repackages them.\n\n## Key Contracts\n\n- **Dependency changes in root `pyproject.toml` that affect client-side code must be mirrored in `client/pyproject.toml`.** This is the most common source of build failures.\n- **New imports in `src/prefect/` can break this build** if they pull in server-only dependencies. The build strips server code, so any import that reaches `server/database`, `server/models`, etc. from client-side code will fail.\n- **The build is tested automatically on every PR** via `.github/workflows/prefect-client.yaml`.\n\n## How It Works\n\n`build_client.sh` copies `src/prefect/` into a temp directory, **deletes** server-only and CLI code, then builds with `client/pyproject.toml`. The resulting package has the same version as `prefect` but fewer dependencies.\n\n### What gets removed\n\n- `cli/` — entire CLI\n- `server/` — database, models, orchestration, schemas, services, utilities (keeps only `server/api/`)\n- `deployments/recipes/` and `deployments/templates/`\n- `testing/`\n\n## Build Triggers\n\n- **PR created** — CI builds and smoke-tests\n- **GitHub release published** — CI builds and publishes to PyPI (same version as `prefect`)\n- **Manual** — `bash client/build_client.sh`\n\nIf the CI build fails, reproduce locally with `bash client/build_client.sh` and run the smoke tests (`client_flow.py`, `client_deploy.py`).\n\n## Related\n\n- `src/prefect/client/` → Actual client SDK source code\n- Root `pyproject.toml` → Must stay in sync with `client/pyproject.toml` for shared dependencies\n\n<!-- File: docs/AGENTS.md (Tokens: ~1694 | Category: root-instruction) -->\n# Prefect Documentation\n\nStructural context for any agent working in `docs/`. For the full writing guide (page types, components, code testing, style), use the `/write-docs` skill.\n\n## Platform\n\n[Mintlify](https://mintlify.com/) docs published to [docs.prefect.io](https://docs.prefect.io). All files use `.mdx` (Markdown + JSX). Site config lives in `docs/docs.json`.\n\n## Directory structure\n\n```\ndocs/\n  v3/                     # Primary docs for Prefect 3.x\n    get-started/          # Installation, quickstart\n    concepts/             # Core concepts (flows, tasks, states, deployments, etc.)\n    how-to-guides/        # Practical guides organized by category\n    advanced/             # Advanced topics\n    examples/             # Auto-generated from examples/ Python files — do NOT edit directly\n    api-ref/              # API reference — mix of auto-generated and hand-authored\n      python/             # SDK reference (auto-generated — do NOT edit directly)\n      cli/                # CLI command reference (auto-generated — do NOT edit directly)\n      rest-api/           # REST API docs (server/ and cloud/) — endpoint pages auto-generated; index.mdx overview pages are hand-authored\n      events/             # Events reference catalog — hand-authored, editable\n    release-notes/        # Version release notes\n    img/                  # Images organized by section\n  integrations/           # Integration-specific docs (prefect-aws, prefect-gcp, etc.)\n  contribute/             # Contributor guides\n  snippets/               # Reusable MDX snippets imported across pages\n  images/                 # Legacy images\n  logos/                  # Brand assets\n  styles/                 # Vale linting styles\n  resources/              # Unlisted pages (hidden: true) outside the v3/ versioning tree\n```\n\n## Auto-generated content — do not edit\n\n- `v3/examples/` — generated from top-level `examples/` Python files by `generate_example_pages.py`\n- `v3/api-ref/python/`, `v3/api-ref/cli/` — generated API reference (Python SDK, CLI)\n- `v3/api-ref/rest-api/` — individual endpoint pages are auto-generated; the `index.mdx` files at `rest-api/` and `rest-api/server/` are hand-authored and may be edited\n- `v3/api-ref/events/` is **hand-authored** and should be edited directly when event schemas change\n- `integrations/<name>/api-ref/` — generated per-integration API reference via `mdxify` (e.g., `integrations/prefect-kubernetes/api-ref/`); regenerated on each integration release\n\n## File format\n\nEvery `.mdx` file starts with YAML frontmatter:\n\n```yaml\n---\ntitle: Page Title\ndescription: Brief description for SEO and navigation\nsidebarTitle: Optional shorter sidebar label   # optional\nicon: icon-name                                # optional, Mintlify icon\nmode: wide                                     # optional; use \"custom\" for raw JSX/HTML layouts\nhidden: true                                   # optional; unlisted page — no nav registration needed\nkeywords: [\"keyword1\", \"keyword2\"]             # optional, for search\n---\n```\n\nFrontmatter keys are always lowercase. The `title` renders as the page's H1, so start body content at `##` — do not add another H1.\n\n## Navigation\n\nAll pages must be registered in `docs/docs.json` under `navigation.tabs`. When adding a page, add its path (without `.mdx` extension) to the appropriate group.\n\n## Links\n\nUse absolute paths from the docs root without `.mdx`:\n\n```mdx\nSee the [flows documentation](/v3/concepts/flows) for details.\n```\n\nDo not use relative paths or include `.mdx` in links.\n\n## Redirects\n\nWhen renaming or moving a page, add a redirect in `docs/docs.json` `redirects` array so existing links continue to work. Never remove existing redirects unless you are certain the old URL has no inbound traffic. Paths should not include `.mdx`.\n\n## Terminology and casing\n\nPreferred terms are enforced by Vale via `docs/styles/CustomStyles/WordList.yml`. Key entries:\n\n- \"Prefect Cloud\" (not \"Prefect cloud\")\n- \"Prefect server\" (not \"Prefect Server\")\n- \"infrastructure\" (not \"infra\")\n- \"Kubernetes\" (not \"k8s\")\n- \"open source\" (not \"open-source\")\n\n## Versioning\n\nAll new content goes in `docs/v3/`. Do not create pages outside `v3/` for current Prefect 3.x features. Exception: unlisted pages (`hidden: true`) can live in `docs/resources/`.\n\n## Local development\n\n```bash\njust docs     # Start the dev server at localhost:3000\njust links    # Check for broken links\njust lint     # Run Vale linter\n```\n\n## Key rules\n\n1. **Do not edit auto-generated files.** Pages under `v3/examples/`, `v3/api-ref/python/`, `v3/api-ref/cli/`, `v3/api-ref/rest-api/`, and `integrations/<name>/api-ref/` are generated from source code. The exception is `v3/api-ref/events/`, which is hand-authored and should be edited when event schemas change.\n2. **Register new pages in `docs/docs.json`.** An unregistered page won't appear in navigation. Exception: pages with `hidden: true` are unlisted and do not require navigation registration.\n3. **Use `.mdx` extension** for all new documentation files.\n4. **Use Mintlify components** (`<Note>`, `<Tabs>`, `<Steps>`, etc.) rather than Markdown-native admonition syntax.\n5. **Keep code examples working.** They are tested in CI via `pytest-markdown-docs`. Two skip mechanisms exist:\n   - Per-block: add `{/* pmd-metadata: notest */}` above the fenced code block when a single example can't run in isolation.\n   - Per-file: add the path to `SKIP_FILES` in `docs/conftest.py` when an entire page requires real external infrastructure (a live database, a dbt project and profiles, real API credentials). Integration pages almost always fall into this category.\n6. **Use absolute link paths** without file extensions (e.g., `/v3/concepts/flows`).\n7. **Check for existing snippets** in `snippets/` before duplicating content.\n8. **Start body content at `##`.** The frontmatter `title` renders as H1; do not add another H1 in the body.\n9. **Document and mark Cloud-only features.** Some features are only available in Prefect Cloud and have no open source equivalent (SSO, audit logs, incidents, SLAs, the `send-email-notification` automation action, etc.). These originate in the `nebula` repo, so they are documented by Prefect staff and agents rather than external contributors. Make sure they are documented here and marked so customers and downstream consumers (such as the Terraform provider and SDKs) can discover them. Conventions:\n   - **Where Cloud-only guides live.** Account, workspace, and user management guides live under `v3/how-to-guides/cloud/`. Prefer this location for new Cloud-only how-to content.\n   - **Mark the feature** when it appears on a page that also covers open source behavior (for example a shared concept page), so readers can tell the editions apart. Use one of:\n     - A Cloud badge on its own line, directly above the page or section it marks: `<span class=\"badge cloud\"></span>`. It renders a standalone \"Prefect Cloud\" label and the span is intentionally empty; put a blank line before the following prose so it scopes the whole section rather than a single sentence.\n     - A `<Note>This action is only available in Prefect Cloud.</Note>` callout for inline cases (e.g. a single table row or variable).\n\n<!-- File: integration-tests/AGENTS.md (Tokens: ~924 | Category: root-instruction) -->\n# Integration Tests\n\nEnd-to-end tests that require a live Prefect server and verify the full orchestration pipeline across process boundaries.\n\n## Purpose & Scope\n\nThese tests cover scenarios that unit tests cannot: real server ↔ worker communication, subprocess flow execution, cancellation across process boundaries, event delivery, and scheduling statefulness.\n\nThey do NOT duplicate unit tests in `tests/`. If a behavior can be tested in isolation, it belongs there.\n\n## Running\n\n```bash\n# Integration tests are excluded from the default testpaths in pyproject.toml — they will NOT run with uv run pytest tests/\nuv run pytest integration-tests/\nuv run pytest integration-tests/test_nested_cancellation.py\n```\n\nRequirements:\n- `PREFECT_API_URL` must point to a running Prefect server (check with `prefect config view`)\n- `uv` must be available in `PATH`\n\nSome tests accept additional env vars: `SERVER_VERSION` (skip version-specific tests), `PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE`, `PREFECT_API_AUTH_STRING`.\n\n## Structure\n\nNo shared `conftest.py`. Each test file is self-contained with its own helpers and fixtures inline. There are no pytest fixtures shared across files.\n\n## Usage Patterns\n\n**Poll, don't assert synchronously.** Hook execution, state transitions, and marker-file writes are independent side effects of the same cancel/complete sequence — the API state can become visible before the hook's file is written. Use `_wait_for()` instead of a bare `assert`:\n\n```python\n# Wrong — races on rare timing:\nassert Path(marker_dir, HOOK_MARKER).exists()\n\n# Right — polls until satisfied or timeout:\n_wait_for(\n    lambda: Path(marker_dir, HOOK_MARKER).exists(),\n    timeout=30,\n    message=\"Hook did not write its marker.\\n\" + _worker_output(log_path),\n)\n```\n\n**Marker files for cross-process state.** Flows running in subprocesses write files to a shared `tmp_path` to signal that a state was reached. Name markers with constants (`PARENT_HOOK_MARKER`, `CHILD_STARTED_MARKER`, etc.) and document them at the top of the file.\n\n**Subprocess invocations use `uv --isolated`.** All CLI calls go through `uv.find_uv_bin()` with `--isolated` to get a clean environment:\n\n```python\nsubprocess.run([uv.find_uv_bin(), \"run\", \"--isolated\", \"prefect\", \"worker\", \"start\", ...])\n```\n\n`PREFECT_API_URL` is inherited from the calling process's env — it still needs to be set.\n\n**Unique work pool names.** Always suffix with `uuid4()` to avoid conflicts across parallel test runs.\n\n**Explicit cleanup in `finally`.** Deployments, work pools, and subprocesses must be cleaned up manually — there is no pytest fixture teardown:\n\n```python\ntry:\n    # set up pool, deployment, worker, run assertions\nfinally:\n    client.delete_work_pool(pool_name)\n    proc.terminate()\n    try:\n        proc.wait(timeout=5)\n    except subprocess.TimeoutExpired:\n        proc.kill()\n```\n\n## Anti-Patterns\n\n- Don't assert synchronously on hook markers or other side effects right after triggering a cancellation — always poll.\n- Don't use fixed `asyncio.sleep()` delays as a substitute for `_wait_for()` — they either waste time or still race.\n- Don't share state between test files via module-level globals — each file is standalone.\n- Don't use subprocess CLI for infrastructure setup/teardown (work pool CRUD, deployment creation) — use `get_client(sync_client=True)` API calls instead. Subprocess is only for testing cross-process behavior (starting workers, executing flow runs in a separate process).\n\n## Pitfalls\n\n- `PREFECT_API_URL` not set produces cryptic errors, not a helpful configuration message. Check it first.\n- These tests are slow (seconds to minutes per test) and intentionally excluded from the default `testpaths` in `pyproject.toml`.\n- Process `terminate()` sends SIGTERM but the subprocess may not exit immediately — always `wait(timeout=...)` and fall back to `kill()`.\n- WebSocket event subscriptions are not active until the `async with get_events_subscriber(...)` context establishes the server connection — events emitted before that happens are silently lost. Signal readiness from *inside* the subscription context using a `threading.Event`, and `assert ready.wait(timeout=30)` before triggering any events in the test.\n\n<!-- File: tests/AGENTS.md (Tokens: ~1214 | Category: root-instruction) -->\n# Test Suite\n\nTests for all Prefect components. Directory structure mirrors `src/prefect/`.\n\n## Key Contracts\n\n- **Server and client test fixtures should not mix.** Server-side tests use a stripped-down client. Do not use `prefect_client` (the full client fixture) in server tests.\n- **Prefer real operations over mocks.** Use real flows, deployments, and flow runs where possible. Reserve `unittest.mock` for external services and time-sensitive operations.\n- **Tests must be deterministic.** No reliance on timing, ordering, or external state.\n- **Both SQLite and PostgreSQL are tested in CI.** Database-related tests run against both.\n\n## Essential Commands\n\n```bash\nuv run pytest tests/                          # Run all tests\nuv run pytest tests/path.py -k test_name      # Run specific test\nuv run pytest tests/module/ -n4               # Run in parallel\nuv run pytest tests/path.py -x                # Stop on first failure\nuv run pytest tests/path.py -x --tb=short     # Compact tracebacks\n```\n\n## Important Fixtures\n\nShared fixtures live in `fixtures/` (see fixtures/AGENTS.md) and root `conftest.py`. The key distinction:\n\n- **Client-side tests** use `prefect_client` (full SDK client). Do not use in server tests.\n- **Server API tests** use `client` / `test_client` (raw httpx/FastAPI against an ephemeral server)\n- **Server model/orchestration tests** use `session` (async SQLAlchemy) and pre-built ORM fixtures (`flow`, `flow_run`, `task_run`, `deployment`, etc.)\n- `test-projects/` — Sample projects used by CLI/deploy tests\n\n## Testing Guidelines\n\n### Database isolation\n\nTests do not get a clean database by default. If a test depends on the DB starting empty — it counts rows, lists \"all X\", or asserts on the absence of records — opt in with `@pytest.mark.clear_db`:\n\n```python\n@pytest.mark.clear_db                # per-test\nasync def test_count_flows(): ...\n\nclass TestFlowAPI:                   # per-class\n    pytestmark = pytest.mark.clear_db\n\npytestmark = pytest.mark.clear_db    # whole module\n```\n\nTests that create resources with UUID-randomized names, filter by IDs they own, or only interact with responses they create themselves usually do not need this marker. Skipping the clear yields a 25–100% suite speedup, so prefer not adding it unless required.\n\nTo check whether a marked file still needs the marker, run it with `--no-clear-db`:\n\n```bash\nuv run pytest tests/path/to/file.py --no-clear-db -x\n```\n\nIf it passes, delete the `pytestmark` (or per-test marker) and commit.\n\n### PREFECT_HOME cleanup\n\n`PREFECT_HOME` is a single temp directory created once per test session (`pytest_sessionstart`), not reset between tests. A test that writes a file directly into it (e.g. a PID file) must delete it in fixture teardown, or later tests in the same session can see it as real state.\n\n### Event assertions\n\nCreating a domain object emits a lifecycle event: building a `flow`, `work_pool`, `variable`, block, concurrency limit, etc. (via fixture or model call) emits `prefect.<object>.{created,...}`. Server tests that assert on `AssertingEventsClient` totals or ordering must `AssertingEventsClient.reset()` after fixture setup, so they count only the events from the action under test rather than the events emitted while building fixtures.\n\n### Type Hints\n- Full type hints on all test functions and fixtures (Python >=3.12 style: `dict[str, str]`)\n- Return type hints on fixtures, omit `-> None` on test functions\n\n### Mocking Strategy\n- Use `unittest.mock` only when necessary (external services, time-sensitive operations)\n- Use `respx` for HTTP response mocking\n\n### Flaky Tests\nWe have a workflow that identifies and fixes tests that flake after merging to main. Check CI test output to see which tests are currently slow or flaky.\n\n**Flow timeout tests**: `pytest-timeout` defaults to SIGALRM on Unix, which interferes with Prefect's own SIGALRM-based flow timeout mechanism. Any test that exercises flow timeouts must opt into thread-based timeouts:\n```python\n@pytest.mark.timeout(method=\"thread\")  # alarm-based pytest-timeout will interfere\nasync def test_flows_fail_with_timeout(self): ...\n```\n\nWhen combining `timeout_seconds` flows with concurrency, use a generous timeout (≥ 2s): the heartbeat-thread setup runs inside the flow's timeout scope and can exhaust a tight timeout before the flow body starts, causing pre-`yield` cancellation on contended CI runners.\n\nUse `retry_asserts` from `prefect._internal.testing` to handle timing-sensitive assertions. Two patterns:\n\n- **Retrying assertions for async event propagation** (most common): wrap the assertion inside `with attempt:` so it retries until the event arrives.\n  ```python\n  async for attempt in retry_asserts(max_attempts=5, delay=0.5):\n      with attempt:\n          callback.assert_called_once_with(flow_run_id)\n  ```\n- **Retrying HTTP requests** (`hosted_api_client` tests): SQLite \"database is locked\" 503 errors can occur due to concurrent access. Retry the HTTP request inside the loop; keep the result assertions *outside* so a wrong result is never masked.\n\n## Related\n\n- `src/prefect/testing/` → Test utilities shipped with the SDK\n- `integration-tests/` → End-to-end tests requiring a running server\n- `ui-v2/e2e/` → Playwright UI tests (see ui-v2/e2e/AGENTS.md)\n\n<!-- File: ui-v2/AGENTS.md (Tokens: ~1908 | Category: root-instruction) -->\n# Prefect UI v2 - React Migration\n\nThis is the new React-based Prefect UI, migrating from the legacy Vue application with minimal visual and functional changes.\n\n## Project Structure\n\n```\nprefect/ui-v2/\n├── src/\n│   ├── api/           # API queries, mutations, and mocks\n│   ├── auth/          # Authentication state, AuthProvider, useAuth hook\n│   ├── components/    # React components organized by domain\n│   ├── graphs/        # Pixi.js run graph rendering engine (ported from @prefecthq/graphs)\n│   ├── hooks/         # Custom hooks for common patterns\n│   ├── lib/           # Utility functions and shared code\n│   ├── mocks/         # Mock data factories\n│   ├── routes/        # Tanstack Router route definitions\n│   ├── storybook/     # Storybook utilities and decorators\n│   └── utils/         # Helper functions and utilities\n├── tests/             # Test utilities and configuration\n├── .storybook/        # Storybook configuration\n└── public/            # Static assets\n```\n\n## Tech Stack\n\n- **React** with TypeScript\n- **Tailwind CSS** - styling\n- **shadcn/ui** - UI component library\n- **Tanstack Query** - API state management\n- **Tanstack Router** - routing\n- **Tanstack Table** - table state management\n- **react-hook-form** - form state management\n- **Recharts** - charts and data visualization\n- **Pixi.js** - WebGL canvas rendering for run graphs (`src/graphs/`)\n- **Vitest** - testing framework\n- **Storybook** - component development and documentation\n- **MSW** - API mocking\n\n## General Principles\n\n- Prefer using functionality from third party libraries over custom implementations\n- Prefer to colocate components in the same file as long as the file is less than 750 lines\n\n## Development Workflow\n\n### Development Process\n\n1. **Start development server**: `npm run dev` (runs on http://localhost:5173/)\n2. **Write tests first** for new components and hooks before implementation\n3. **Implement** the component/hook following existing patterns\n4. **Create Storybook story** to document component variants\n5. **Verify functionality** in the browser at http://localhost:5173/\n6. **Compare with legacy Vue** implementation at http://localhost:4200/ for consistency\n\n### Pre-commit Checklist\n\nBefore committing any changes, always run:\n\n1. **Format and lint**: `npm run check` (Biome formatting and linting)\n2. **Additional linting**: `npm run lint` (ESLint rules)\n3. **Build verification**: `npm run build` (ensure no build errors)\n4. **Test verification**: `npm test` (run relevant tests)\n\n### Performance Tips\n\n- Run **single tests** for faster feedback: `npm test -- ComponentName`\n- Run **lint on single files** for performance: `npx eslint src/path/to/file.ts --fix`\n- Use **Storybook** for isolated component development: `npm run storybook`\n\n### Browser Testing\n\n- **Primary development**: http://localhost:5173/\n- **Legacy comparison**: http://localhost:4200/\n- **Component documentation**: http://localhost:6006/ (Storybook)\n\n## Common Commands\n\n- `npm run dev` - Start development server\n- `npm run build` - Build production bundle\n- `npm run test` - Run tests\n- `npm run check` - Run linter and formatter (Biome)\n- `npm run lint` - Run ESLint\n- `npm run storybook` - Start Storybook\n- `npm run service-sync` - Sync API types from backend\n\n## Code Organization\n\n- **Flat structure**: Components, tests, and stories live together\n- **Index exports**: Each directory exports public APIs via `index.ts`\n- **Domain organization**: Components organized by Prefect domain (flows, deployments, etc.)\n- **Namespace awareness**: Component names consider their directory context\n\n## Quality Standards\n\n- **Always write tests** for new components and hooks\n- **Always create Storybook stories** for new components\n- **Run `npm run check`** after creating components/hooks\n- **Check functionality** in browser during development\n- **Mock all API calls** using MSW\n\n## API Integration\n\n- Use **`useSuspenseQuery`** over `useQuery` for declarative code; use `useQuery` when the component must silently return `null` while loading rather than suspend the tree (e.g., optional or promotional components that should disappear rather than show a skeleton)\n- **Query factories** in `/api` directories with standardized key patterns\n- **Mutation hooks** in `/api` directories\n- **No data transformation** in query factories - do it in components\n- **Duration fields** (`estimated_run_time`, `total_run_time`, etc.) are returned in **seconds** by the API. Prefer `secondsToApproximateString`/`secondsToString` from `@/utils/seconds` for display — they take raw seconds directly. `humanizeDuration` and similar JS libraries expect milliseconds instead, so multiply by 1000 before passing to them\n\n## Forms\n\n- **react-hook-form** for form state\n- **zod** for validation\n- **Form** and **FormField** components from shadcn/ui\n- **Stepper** component for wizard flows\n- **Forms bound to refetched queries**: Entity queries (deployments, etc.) refetch on a 30-second interval and on window focus, returning new object references each time. Use `useState` lazy initializers to capture default values once — do not sync form state via `useEffect`, which overwrites in-flight user edits on every refetch. Add `key={entity.id}` on the form component so it fully resets when the entity changes.\n- **Zod v4**: `z.record()` requires an explicit key schema — `z.record(z.string(), z.unknown())`, not the v3-style `z.record(z.unknown())`. `ZodError` instances expose `.issues`, not the removed `.errors`.\n\n## Testing\n\n- **Vitest** with **@testing-library/react**\n- All API calls mocked with **MSW**\n- Mock factories using **@ngneat/falso**\n- Run single tests for performance: `npm test -- ComponentName`\n\n## Git Workflow\n\n- Branch naming: `ui-v2/feature-description`\n- Succinct commit messages\n- PR descriptions mention \"Related to #15512\"\n- Never commit directly to `main`\n\n## Styling for Light and Dark Mode\n\nThe UI supports both light and dark themes. To ensure components render correctly in both modes:\n\n### Use Semantic Color Tokens\n\nAlways use Tailwind's semantic color classes that automatically adapt to the current theme instead of hardcoded color values:\n\n| Instead of | Use |\n|------------|-----|\n| `bg-gray-100`, `bg-gray-200` | `bg-muted` |\n| `bg-white` | `bg-background` or `bg-card` |\n| `text-gray-500`, `text-gray-600` | `text-muted-foreground` |\n| `text-gray-900`, `text-black` | `text-foreground` |\n| `border-gray-200`, `border-gray-300` | `border-border` or `border-muted` |\n\n### For Dividers and Subtle Elements\n\nUse opacity modifiers with semantic colors for subtle visual elements like dividers:\n- `bg-muted-foreground/30` for subtle divider lines\n- `border-border` for standard borders\n\n### Prose Content in Dark Mode\n\nTailwind's `prose` class (`@tailwindcss/typography`) does **not** automatically invert in dark mode. Any element using `prose` must also include `dark:prose-invert`:\n\n```tsx\n<div className=\"prose dark:prose-invert\">...</div>\n```\n\n### CodeMirror Editors\n\n`@uiw/react-codemirror` does not follow the app theme automatically. Any component using `useCodeMirror` must explicitly read and pass the theme:\n\n```tsx\nconst { resolvedTheme } = useTheme(); // from \"next-themes\"\nuseCodeMirror({ theme: resolvedTheme === \"dark\" ? \"dark\" : \"light\", ... });\n```\n\n### Avoid Hardcoded Colors\n\nNever use hardcoded gray scale colors (e.g., `bg-gray-100`, `text-gray-500`) as these will not adapt to dark mode and can make text unreadable or create jarring visual contrast.\n\n### Testing Dark Mode\n\nAlways verify components in both light and dark mode:\n1. Use the theme toggle in Settings to switch between modes\n2. Check that all text remains readable\n3. Verify backgrounds blend appropriately with the overall theme\n4. Ensure sufficient contrast for interactive elements\n\n## Architecture Notes\n\n- **Suspense-first**: Use suspense queries to avoid loading states\n- **Type safety**: Never use `as unknown` or disable ESLint\n- **Pure functions**: Keep utilities side-effect free\n- **Composition**: Prefer composition over complex inheritance\n\n<!-- File: .claude/skills/agents-md-sync/SKILL.md (Tokens: ~3123 | Category: anthropic-skill) -->\n---\nname: agents-md-sync\ndescription: Analyze code changes on the current branch and recommend updates to AGENTS.md files that have become stale. Use this skill before creating a PR, when the user asks to check AGENTS.md freshness, or when preparing an AGENTS.md update after a PR merges to main. Trigger whenever the user mentions syncing, updating, or checking AGENTS.md files, or when they're about to create a PR that touches code structure (new modules, renamed directories, changed commands, modified architecture).\n---\n\n# AGENTS.md Sync\n\nDetect when code changes make durable AGENTS.md guidance stale and produce a report with specific recommendations. Treat AGENTS.md files as operating manuals for future agents, not changelogs for recent diffs.\n\n## When to use\n\n- Before creating a PR — check if the branch's changes warrant AGENTS.md updates\n- After a PR merges to main — audit whether merged changes left AGENTS.md files outdated\n- On explicit request — \"are the AGENTS.md files up to date?\"\n\n## Workflow\n\n### 1. Determine the diff\n\nFigure out what changed relative to the base branch. The approach depends on context:\n\n- **On a feature branch (pre-PR):** diff against main\n  ```bash\n  git diff main...HEAD --name-status\n  git diff main...HEAD\n  ```\n- **After a merge to main:** the user should specify which PR or commit range to audit. Use the merge commit or PR number to get the diff:\n  ```bash\n  gh pr diff <number>\n  ```\n- **Explicit check:** if the user just says \"check AGENTS.md\", diff against main\n\n### 2. Map changes to AGENTS.md territories\n\nEach AGENTS.md file \"owns\" the directory it lives in and all subdirectories (unless a child directory has its own AGENTS.md). Build a list of which AGENTS.md files are relevant by walking up from each changed file to find the nearest AGENTS.md.\n\nExample: a change to `src/prefect/server/api/flows.py` is owned by `src/prefect/server/AGENTS.md` (if it exists), otherwise `src/prefect/AGENTS.md`.\n\nOnly analyze AGENTS.md files that have at least one changed file in their territory. Also include parent AGENTS.md files if structural changes (new directories, moved files) affect the directory tree they document.\n\n### 3. Check for missing AGENTS.md files\n\nBefore analyzing existing AGENTS.md files, check whether any changed directories *should* have their own AGENTS.md but don't. New AGENTS.md files should be rare. Recommend one only when the directory has both:\n\n- A real ownership boundary that a future agent needs to recognize before editing\n- Hidden conventions, non-obvious contracts, or recurring pitfalls that cannot be learned quickly from reading the code\n\nLook at the directories containing changed files. For each one that lacks an AGENTS.md, check:\n1. **Ownership boundary**: Does this directory represent a responsibility shift with different contracts than its parent?\n2. **Hidden knowledge**: Are there non-obvious patterns, invariants, conventions, or failure modes that a developer would not learn quickly from code?\n3. **Durability**: Will this guidance still matter after the triggering PR is old news?\n4. **Hierarchy fit**: Would this belong better in an existing parent AGENTS.md instead?\n\nDirectory size and sibling AGENTS.md files can be weak signals, but they are never sufficient on their own. Do not recommend a new AGENTS.md just because a directory has 5+ files, gained a new module, or has sibling directories with AGENTS.md files.\n\nWhen the case is not high-confidence, do not create the file. Capture the possible update as a recommendation instead, with the missing evidence or question that would make it actionable.\n\nWhen recommending a new AGENTS.md, use the Explore agent to read the directory's code and draft the file using this template:\n\n```markdown\n# <Module Name>\n\n<One-sentence purpose statement.>\n\n## Purpose & Scope\n\nWhat this module does. Explicit responsibility boundaries.\nWhat it does NOT do (prevents scope creep).\n\n## Entry Points & Contracts\n\nKey APIs, functions, classes that external consumers use.\nInput/output contracts. Invariants that must hold.\n\n## Usage Patterns\n\nCanonical examples of correct usage.\n\"If you need to do X, here's how.\"\n\n## Anti-Patterns\n\nWhat NOT to do. Common mistakes. Each should be a real mistake, not hypothetical.\n\n## Pitfalls\n\nNon-obvious gotchas. Implicit assumptions.\n\"You'd think X, but actually Y because Z.\"\n```\n\nThe initial content must be concise and durable. Do not include `[ASK]` placeholders, file lists, changelog context, or speculative guidance. If the hidden knowledge cannot be stated confidently, write a recommendation instead of creating the file.\n\n### 4. Analyze each relevant AGENTS.md\n\nAGENTS.md files form a hierarchy — when an agent loads any file, all ancestor files load too, creating a T-shaped view (broad context at the top, specific detail where the agent works). This has two implications for the sync check:\n\n**Least common ancestor rule**: Shared knowledge should live at the shallowest AGENTS.md that covers all paths needing it. If the same fact appears in multiple sibling AGENTS.md files, flag it — it should move to their parent. Conversely, if a parent AGENTS.md contains detail that only applies to one child directory, suggest moving it down.\n\n**Upward propagation**: When a child AGENTS.md changes (or a new one is created), check whether the parent needs updating — either to add a cross-reference to the new child, or to re-summarize what the child directory does. Parent nodes should summarize their children's responsibilities, not duplicate their details.\n\nFor each AGENTS.md in scope, read it fully, then compare its claims against the diff **and** the current source code. Look for these categories of issues:\n\n**Accuracy** — claims in AGENTS.md that don't match the actual code, regardless of whether the diff caused the discrepancy:\n- Described behaviors that don't match what the code actually does (e.g., \"renews at 75% of duration\" when it actually renews immediately then sleeps 75%)\n- Function signatures or parameters listed that are wrong or incomplete\n- Responsibilities attributed to the wrong layer or module\n- Error handling or failure modes described incorrectly\n\nFor claims that are verifiable (specific behaviors, function signatures, which module does what), read the source file and confirm. Don't trust that existing AGENTS.md content was ever correct — it may have been wrong from the start.\n\n**Signal density** — content that duplicates what's discoverable from code rather than surfacing hidden knowledge:\n- Full function signatures that just repeat the code (the *contracts* and *gotchas* around those functions are the high-signal parts)\n- Trivial usage examples that match what's in docstrings or is obvious from the API\n- File-by-file directory listings that `ls` would show — the *layering concept* or *architectural invariant* matters, not the enumeration\n- Content that a developer would learn in 30 seconds of reading the source\n\nAGENTS.md should capture what's *not* visible in the code: invariants, hidden contracts, non-obvious failure modes, things that look one way but behave another.\n\nA behavior discovered in one changed function is not AGENTS-worthy by default.\nPromote it only if it exposes a subsystem-level editing rule, a cross-file\ncontract, or a recurring failure mode future agents need before choosing\nwhich implementation to read. Otherwise prefer a code comment, docstring,\ntest name, or no documentation change.\n\nIf the same guidance is already present in nearby code comments, docstrings, or tests, AGENTS.md should usually not repeat it.\n\n**Missing invariants** — implicit contracts the code relies on that aren't documented:\n- Parallel implementations that must stay in sync (e.g., sync and async versions of the same module)\n- Ordering requirements or sequencing constraints\n- Singleton behaviors or shared mutable state\n- Cleanup responsibilities and what happens when they're skipped\n- \"This looks stateless but actually depends on X\"\n\n**Structural drift** — the AGENTS.md describes an ownership boundary, durable package layout, or module responsibility that no longer matches reality:\n- Directories or packages added/removed/renamed in a way that changes responsibility boundaries\n- New architectural layers or cross-file contracts not mentioned\n- Removed components still listed as active responsibilities\n\n**Command drift** — documented commands that may no longer work or are incomplete:\n- Build/test/run commands referencing changed entry points\n- New tooling or scripts not mentioned\n\n**Convention drift** — code patterns or conventions described in AGENTS.md that the diff contradicts:\n- New patterns established by the changes that aren't documented\n- Existing conventions the changes deprecate or replace\n\n**Description drift** — prose descriptions that no longer accurately characterize the code:\n- Component descriptions that miss new responsibilities\n- Architecture notes that don't reflect refactoring\n\n**Hierarchy drift** — content living at the wrong level in the AGENTS.md tree:\n- Knowledge duplicated across sibling AGENTS.md files that should be in their parent (least common ancestor)\n- Parent-level detail that only applies to one child directory\n- Parent summaries of child directories that no longer match after changes\n\nFor each finding, check whether it's actually stale — read the current state of the filesystem (not just the diff) to confirm. A diff showing a new file, helper, flag, or one-off fix doesn't mean AGENTS.md is wrong if AGENTS.md intentionally omits that level of detail.\n\nOnly recommend or apply updates for high-confidence, lasting guidance:\n- Architectural boundaries\n- Non-obvious invariants\n- Cross-file contracts\n- Recurring failure modes\n- Commands or conventions that future agents are likely to need\n\nDo not document:\n- One-off implementation details or temporary bug context\n- Facts obvious from reading names, imports, or nearby code\n- File lists or every new module\n- Changelog-style summaries of the triggering diff\n- Advice that only matters for the current PR\n\n### 5. Produce the report\n\nOutput a concise report grouped by AGENTS.md file. For each file, list findings with:\n- **What's stale** — the specific line or section\n- **Why** — which change caused it\n- **Suggested fix** — the concrete text to add, remove, or change\n\nFormat:\n\n```markdown\n## AGENTS.md Sync Report\n\n### New AGENTS.md recommended: `src/prefect/utilities/`\n\nThis directory now owns a distinct retry protocol used by multiple callers, and contributors must preserve its ordering invariant. Suggested outline:\n- Purpose and ownership boundary\n- Ordering invariant that callers rely on\n- Failure mode to test when changing it\n\n### `src/prefect/server/AGENTS.md`\n\n1. **[Accuracy]** Lease renewal described as \"renews at 75% of duration\" but code renews immediately then sleeps 75%\n   - Caused by: incorrect from initial creation\n   - Suggested fix: \"renews immediately on entry, then sleeps for 75% of `lease_duration` between renewals\"\n\n2. **[Signal density]** Full function signatures duplicate the code — remove parameter lists, keep contracts\n   - Suggested fix: Replace `concurrency(names, occupy=1, ...)` with `concurrency()` and describe the non-obvious behaviors instead\n\n3. **[Missing invariant]** Sync and async implementations must stay in lockstep but this isn't documented\n   - Suggested fix: Add \"Any behavior change to `_asyncio.py` must be mirrored in `_sync.py`\"\n\n4. **[Structural]** New directory `src/prefect/server/events/` not listed in directory structure\n   - Caused by: `src/prefect/server/events/` added in this branch\n   - Suggested fix: Add `events/` to the directory listing with description\n\n### `./AGENTS.md` (root)\nNo changes needed.\n```\n\nIf nothing is stale, say so clearly — don't manufacture findings.\n\n### 6. Offer next steps\n\nAfter presenting the report, offer:\n- **Apply fixes** — make the suggested edits directly\n- **Create a follow-up PR** — if this is a post-merge audit, offer to create a branch and PR with just the AGENTS.md updates\n- **Skip** — if the changes are minor or the user disagrees with the suggestions\n\n## Reactive mode\n\nOutside of diff-driven analysis, if during normal development you discover missing context that should be in an AGENTS.md, propose an addition. Signs of missing context:\n\n- You spent nontrivial time reconstructing a durable invariant that could be a one-liner in AGENTS.md\n- You hit a non-obvious error because of an undocumented constraint\n- You discovered a cross-system dependency that isn't mentioned anywhere\n- A code review caught something that AGENTS.md should have prevented\n\nPropose additions like this:\n```\nI discovered that [finding]. This isn't in [path]/AGENTS.md.\n\nProposed addition to the [section] section:\n> [concrete text to add]\n\nShould I add this?\n```\n\n## Quality checks for new or updated AGENTS.md content\n\n- **Compression**: Can any section be shorter without losing information?\n- **Deduplication**: Does anything repeat what a parent AGENTS.md already says? If so, remove it and rely on the hierarchy.\n- **Specificity**: Replace vague statements with concrete ones. Not \"be careful with auth\" but \"place logic after the `require_*` call\".\n- **Target length**: 20-80 lines for new files. If longer, compress or write recommendations instead.\n\n## Important guidelines\n\n- Be conservative — only flag things that are genuinely wrong or missing. AGENTS.md files are intentionally concise and don't need to document every file.\n- Don't suggest adding content that's obvious from the code itself. AGENTS.md captures non-obvious patterns, gotchas, and high-level structure. Equally, flag *existing* content that merely restates the code — full function signatures, trivial examples, and file enumerations are low-signal and should be trimmed or replaced with the hidden knowledge around them.\n- Don't trust that existing AGENTS.md content was ever correct. Verify factual claims (behaviors, signatures, responsibility attribution) against the source code, not just against the diff. Content can be wrong from day one.\n- Don't suggest stylistic rewrites. Focus on factual accuracy and signal density.\n- When in doubt about whether something is stale, check the filesystem to confirm rather than guessing from the diff alone.\n- Respect the existing level of detail in each AGENTS.md. If a file only lists top-level directories, don't suggest adding individual files.\n- Look for undocumented invariants — parallel implementations that must stay in sync, ordering constraints, singleton behaviors, cleanup responsibilities. These are the highest-value additions because they're invisible in code and cause the most breakage when violated.\n\n<!-- File: .claude/skills/backlog-management/SKILL.md (Tokens: ~1155 | Category: anthropic-skill) -->\n---\nname: backlog-management\ndescription: Manage open-source GitHub issue backlogs (especially PrefectHQ/prefect) in batches. Use for backlog cleanup days, stale review, duplicate pruning, missing-info follow-up, and prioritized queue curation across many open issues.\n---\n\n# Backlog Management\n\nUse this skill for batch backlog work, not for deep triage of a single new issue.\n\n## Scope\n\n- Open-source repositories only.\n- Use public, contributor-friendly language.\n- Do not reference internal plans or private project context.\n\n## Default Mode\n\n- Work in batches of 25-100 issues.\n- Start in read-only mode and propose actions first.\n- Apply edits only after approval unless explicitly asked to execute immediately.\n\n## Workflow\n\n1. Build a candidate batch.\n2. Assign one primary action per issue.\n3. Deep-dive only close candidates.\n4. Draft concise comments where needed.\n5. Apply approved edits.\n6. Report outcomes with counts and issue links.\n\n## Two-Pass Review Depth\n\nUse two passes by default:\n\n- Pass 1 (sweep): classify quickly across the full batch.\n- Pass 2 (dig-in): re-review only `close-not-planned` and `close-duplicate` candidates.\n\nDo not finalize close actions from Pass 1 alone.\n\nFor Pass 2, require explicit evidence:\n\n- architecture/status check against current Prefect behavior\n- concrete links (issue comments, PRs, release notes, docs, code)\n- counterevidence (why issue might still be valid)\n- confidence (`low`, `medium`, `high`)\n\nIf evidence is weak or mixed, downgrade close to:\n\n- `needs:details`\n- `needs:mre`\n- `status:stale`\n- `keep-open`\n\nUI replatform exception:\n\n- Prefect currently has both legacy UI code (`ui/`) and the React replatform (`ui-v2/`).\n- For UI issues that appear tied to legacy UI behavior, do not close based only on age/architecture drift until `ui-v2` is GA.\n- Before proposing close, check whether the reported behavior is represented in `ui/`, `ui-v2/`, or both.\n- Default action before GA is `keep-open` (or `status:stale` only if explicitly desired by maintainers).\n\n## Candidate Queries (PrefectHQ/prefect)\n\nUse focused searches:\n\n```bash\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue no:assignee sort:updated-asc\" --limit 100\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue label:status:stale sort:updated-asc\" --limit 100\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue label:bug -label:needs:mre sort:updated-asc\" --limit 100\ngh issue list --repo PrefectHQ/prefect --search \"is:open is:issue label:needs:details sort:updated-asc\" --limit 100\n```\n\n## Action Set\n\nChoose exactly one primary action per issue:\n\n- `keep-open`: still actionable, no immediate label change needed\n- `needs:details`: missing context blocks progress\n- `needs:mre`: bug report lacks minimal reproducible example\n- `status:stale`: inactive and low-signal, not exempt\n- `close-duplicate`: close with canonical issue link\n- `close-not-planned`: close with concise reason when clearly out of scope or no longer actionable\n\n## Deep-Dive Output Format\n\nFor every close candidate, produce this mini-record before execution:\n\n- `issue`: number + title\n- `claim_to_verify`: why it appears closable\n- `current_state_check`: does claim still hold today?\n- `evidence_links`: specific references\n- `counterevidence`: any signal to keep open\n- `recommended_action`: final action after deep-dive\n- `confidence`: low/medium/high\n\n## Real Labels (PrefectHQ/prefect)\n\nOnly use labels that exist in this repo. Key labels for backlog work include:\n\n- `needs:details`\n- `needs:mre`\n- `status:stale`\n- `needs:triage`\n- `question`\n- `bug`\n- `enhancement`\n- `good first issue`\n- `blocked`\n- `status:exempt`\n\nVerify labels before applying changes:\n\n```bash\ngh label list --repo PrefectHQ/prefect --limit 30\n```\n\n## Comment Templates\n\nMissing details:\n\n```text\nThanks for opening this. We need a bit more detail before we can move this forward:\n- expected behavior\n- actual behavior\n- exact steps to reproduce\n```\n\nMissing MRE:\n\n```text\nThanks for the report. Please share:\n1) a minimal reproducible code sample,\n2) full traceback/error text,\n3) output of `prefect version`.\n```\n\nDuplicate close:\n\n```text\nClosing as a duplicate of #<issue-number> so discussion stays in one place.\nIf this is materially different, tag me and comment with details; we can reopen.\n```\n\n## Guardrails\n\n- Do not close issues only because they are old.\n- Do not mark as stale when clear maintainer/reporter activity is recent.\n- Do not apply conflicting labels.\n- Do not over-explain; keep comments short and specific.\n- Do not close legacy-UI issues before `ui-v2` GA unless there is a strong non-UI reason (for example, duplicate with active canonical issue).\n\n<!-- File: .claude/skills/document-changes/SKILL.md (Tokens: ~2041 | Category: anthropic-skill) -->\n---\nname: document-changes\ndescription: Analyze source code changes on the current branch and identify documentation that is stale, inaccurate, or missing. Use before creating a PR to check if docs need updating, or in CI after merges to main to automatically fix docs. Trigger when the user mentions \"doc changes\", \"docs update\", \"check docs\", \"document changes\", or wants to know if code changes affect documentation.\n---\n\n# Document Changes\n\nAnalyze source code changes to find documentation that is stale, inaccurate, or missing, then either report findings or directly apply fixes.\n\n## Modes\n\n- **Report mode (default, local dev):** Produce a structured report of findings with suggested fixes. Offer to apply them.\n- **Edit mode (CI):** Directly apply fixes to existing doc pages. Do not create entirely new pages — flag those as recommendations in the PR body instead.\n\nThe mode is determined by how the skill is invoked. Local interactive use defaults to report mode. CI sets edit mode via the prompt.\n\n## Prerequisites\n\nBefore making any doc edits, read the write-docs skill at `.claude/skills/write-docs/SKILL.md`. All edits must follow its conventions for tone, components, frontmatter, code blocks, and testing directives.\n\n## Workflow\n\n### 1. Determine the diff\n\nFigure out what changed relative to the base branch:\n\n- **On a feature branch (pre-PR):** diff against main\n  ```bash\n  git diff main...HEAD --name-status\n  git diff main...HEAD -- 'src/prefect/' 'src/integrations/'\n  ```\n- **After a merge to main (CI):** read the diff provided at `/tmp/diff.patch`\n- **Explicit check:** diff against main\n\nFilter the diff to only source code changes. Skip:\n- Test files (`**/tests/**`)\n- CI/workflow files (`.github/`)\n- Documentation files (`docs/`, `*.md`, `*.mdx`)\n- Lock files (`uv.lock`, `package-lock.json`)\n- UI files (`ui-v2/`)\n\n### 2. Extract public API surface changes\n\nScan the diff for changes that users would encounter:\n\n**Function and class signatures:**\n- New, renamed, or removed public functions/classes/methods\n- Changed parameters (added, removed, renamed, retyped)\n- Changed default values\n- Changed return types\n\n**CLI commands:**\n- New, renamed, or removed commands (look for `@app.command()`, click/typer decorators)\n- Changed arguments or options\n- Changed help text\n\n**Configuration and settings:**\n- New, renamed, or removed settings (look for `Setting`, `Field` in settings classes)\n- Changed defaults or validation\n- Changed environment variable names\n\n**Behavioral changes:**\n- Changed error types or messages users would see\n- Changed lifecycle behavior (e.g., retry logic, state transitions)\n- Changed defaults that affect runtime behavior\n\n**Skip:**\n- Private/internal symbols (names starting with `_` in `_internal` modules)\n- Type-only changes that don't affect runtime behavior\n- Import reorganizations that don't change the public API\n- Pure refactors with no behavioral change\n\n### 3. Map changes to existing docs\n\nFor each extracted change, search the docs for references. Use parallel searches for efficiency.\n\n**Exclude auto-generated files.** Before searching or editing, filter out all auto-generated doc files. These are maintained by generation scripts and will be updated separately before each release. Never search, flag, or edit these paths:\n- `docs/v3/api-ref/` — entire directory (generated by `scripts/generate_api_ref.py` and `scripts/generate_settings_ref.py`)\n- `docs/v3/examples/` — entire directory (generated by `scripts/generate_example_pages.py`)\n- Any file containing a comment like `This page is generated by` or `automatically generated`\n\n**Search strategy:**\n- Grep `docs/` (excluding auto-generated paths above) for function names, class names, CLI command names, setting names\n- Check concept pages that explain the changed feature's behavior\n- Check how-to guides that demonstrate the changed API\n- Check get-started pages if fundamental APIs changed\n- Check integration docs if integration entry points changed\n\n**Build a findings list with these categories:**\n\n**Stale — docs describe something that changed:**\n- Wrong default value documented\n- Old parameter name or signature\n- Removed feature still documented\n- Behavior description that no longer matches the code\n- Code examples using old API\n\n**Missing — new public API/feature with no doc coverage:**\n- New public function/class with no mention in any doc page\n- New CLI command not documented\n- New setting not listed in configuration docs\n- New feature that extends an existing documented concept\n\n**Broken examples — code blocks that reference changed APIs:**\n- Code blocks using removed or renamed functions\n- Code blocks with old parameter names\n- Code blocks that would produce different output than described\n\n### 4. Produce output\n\n#### Report mode (local dev)\n\nPrint a structured report grouped by doc file:\n\n```markdown\n## Documentation Changes Report\n\n### `docs/v3/concepts/flows.mdx`\n\n1. **[Stale]** Line 45: `@flow(retries=3)` — `retries` parameter renamed to `max_retries` in src/prefect/flows.py\n   - **Suggested fix:** Update parameter name in code example and surrounding prose\n\n2. **[Broken example]** Line 78-85: Code block uses `flow.run()` which was removed\n   - **Suggested fix:** Replace with `flow()` direct invocation\n\n### `docs/v3/how-to-guides/workflows/retries.mdx`\n\n1. **[Stale]** Line 23: \"Default retry delay is 5 seconds\" — default changed to 10 seconds in this branch\n   - **Suggested fix:** Update to \"Default retry delay is 10 seconds\"\n\n### Missing coverage\n\n1. **[Missing]** New `@flow(on_cancellation=...)` hook added — no docs mention this parameter\n   - **Recommendation:** Add a section to `docs/v3/concepts/flows.mdx` under \"Flow lifecycle hooks\" or create a new how-to guide\n\n### No changes needed\n- `docs/v3/get-started/quickstart.mdx` — references checked, all current\n```\n\nAfter presenting the report, offer:\n- **Apply fixes** — make the suggested edits to existing pages (follow write-docs skill conventions)\n- **Skip** — if the user disagrees with findings or wants to handle manually\n\n#### Edit mode (CI)\n\nDirectly apply fixes for **Stale** and **Broken example** findings on existing pages:\n- Skip any file under an auto-generated path (`docs/v3/api-ref/`, `docs/v3/examples/`) or containing a generated-by comment — do not edit these even if they appear stale\n- Read each affected doc file\n- Make targeted, minimal edits to fix the specific issues\n- Do not rewrite surrounding content\n- Do not change tone, style, or structure beyond what's needed\n- For code blocks, ensure the fix is syntactically valid\n- Add `{/* pmd-metadata: notest */}` only if the fixed code genuinely can't be tested\n\nFor **Missing** coverage findings, do not create new pages. Instead, collect them for the PR body.\n\n### 5. Quality gate (edit mode only)\n\nBefore considering edits complete, verify each change:\n- Follows write-docs tone (second person, active voice, no marketing language)\n- Uses Mintlify components correctly (not markdown admonitions)\n- Preserves existing frontmatter (title, description, keywords)\n- Does not add or remove pages from `docs/docs.json`\n- Code blocks are syntactically valid Python/bash\n- Changes are minimal — only what's needed to fix the finding\n\n### 6. Offer next steps (report mode only)\n\nAfter applying fixes (if the user chose to), mention:\n- Run `just lint` in `docs/` to check Vale style\n- Run markdown tests if code blocks were modified\n- Any missing coverage items that need new content written (suggest using the write-docs skill)\n\n## Important guidelines\n\n- **Be conservative.** Only flag things that are genuinely wrong or missing. A doc page that doesn't mention every parameter is fine — it's stale only if it mentions the *wrong* value or a *removed* thing.\n- **Don't rewrite for style.** If the prose is accurate, leave it alone even if you'd write it differently.\n- **Verify before flagging.** Read both the diff and the current doc file. A grep hit doesn't mean the doc is wrong — read the context.\n- **Respect doc scope.** Not every public API needs docs. Flag missing coverage for features users would reasonably expect to find documented, not for every internal helper that happens to be public.\n- **Minimize blast radius in CI.** Small, targeted fixes only. If a finding requires judgment about page structure or new content, leave it as a recommendation rather than an automated edit.\n- **Don't touch auto-generated pages.** Skip the entire `docs/v3/api-ref/` directory (including `settings-ref.mdx`, Python SDK reference, CLI reference, and REST API reference), the entire `docs/v3/examples/` directory, and any file containing a generated-by comment (e.g., `This page is generated by`). These files are regenerated by scripts before each release and must not be edited manually or by automation.\n- **Check code block test directives.** If you modify a code block, check whether it has `pmd-metadata` directives and preserve them. If you're unsure whether a modified block is testable, mark it `notest` and note why.\n\n<!-- File: .claude/skills/write-docs/SKILL.md (Tokens: ~3936 | Category: anthropic-skill) -->\n---\nname: write-docs\ndescription: Comprehensive guide for writing and updating Prefect documentation. Use when creating new doc pages, updating existing docs, or working with Mintlify components and code example testing.\n---\n\n# Writing Prefect Documentation\n\nThis guide covers everything needed to write, update, and test Prefect documentation pages. For structural context (directory layout, navigation, links, local dev commands), see `docs/AGENTS.md`.\n\n## Page types\n\nEach section of the docs serves a distinct purpose. Place new content in the right section and match its tone and structure.\n\n### Get Started (`v3/get-started/`)\n\nOnboarding pages for new users. Content should be linear, opinionated, and get the reader to a working result as fast as possible. Use `<Steps>` for sequential instructions and `<Tabs>` to offer Cloud vs. self-hosted paths. Minimize explanation — link to Concepts for deeper understanding.\n\n### Concepts (`v3/concepts/`)\n\nExplain **what** something is and **why** it matters. Concepts pages define Prefect's mental model — flows, tasks, states, deployments, events, work pools, etc. Start with a short code example showing the concept in action, then explain the underlying model, lifecycle, and relationships to other concepts. Link to How-to Guides for step-by-step instructions. Do not provide exhaustive procedural walkthroughs here.\n\n### How-to Guides (`v3/how-to-guides/`)\n\nTask-oriented pages that show **how** to accomplish a specific goal. Each page should solve one problem (e.g., \"How to write and run a workflow\", \"How to set up retries\"). Structure as a series of actionable steps with code examples. Meet the reader where they are — do not assume familiarity with Prefect internals. Use the smallest amount of Prefect-specific jargon possible, and explain or link terms when they are unavoidable.\n\nGuides are organized into the following categories:\n\n- **`workflows/`** — Writing, running, and customizing flows and tasks: retries, caching, concurrency, logging, testing, runtime info, state hooks, and artifacts.\n- **`deployments/`** — Creating, scheduling, running, and versioning deployments, including `prefect.yaml` configuration and flow code storage.\n- **`deployment_infra/`** — Running workflows on specific infrastructure: Docker, Kubernetes, serverless platforms (AWS ECS, Azure ACI, GCP Cloud Run), Modal, Coiled, Prefect Managed, and local processes. Also covers work pool management.\n- **`automations/`** — Setting up event-driven automations: creating automations and triggers, chaining deployments via events, custom notifications, and accessing event payloads in flows.\n- **`cloud/`** — Prefect Cloud-specific operations: connecting to Cloud, managing workspaces and users, creating webhooks, and troubleshooting.\n- **`configuration/`** — Configuring the Prefect environment: managing settings, storing secrets, and using variables.\n- **`ai/`** — Using Prefect with AI tooling, such as the Prefect MCP server.\n- **`migrate/`** — Upgrading from older Prefect versions or migrating from other tools like Airflow.\n- **`self-hosted/`** — Running the Prefect server yourself via Docker Compose, the CLI, or on Windows.\n\n### Advanced (`v3/advanced/`)\n\nIn-depth pages for experienced users covering topics like transactions, interactive workflows, infrastructure-as-code, scaling self-hosted deployments, and custom API integrations. These assume familiarity with core concepts and how-to patterns. They can be longer and more detailed than how-to guides.\n\n### Examples (`v3/examples/`)\n\n**Auto-generated — do not edit directly.** Each page is generated from a standalone Python file in the repo's top-level `examples/` directory by `generate_example_pages.py`. To add an example, create a new `.py` file in `examples/` with YAML frontmatter in comments and run `just generate-examples`. See `contribute/docs-contribute.mdx` for the full process.\n\n### Integrations (`integrations/`)\n\nEach integration (e.g., `prefect-aws`, `prefect-gcp`) has its own subdirectory. The `index.mdx` covers installation, credential setup (blocks), and key capabilities. Additional pages cover specific workers, tasks, or SDK reference. Follow the existing pattern: \"Why use it\" section, prerequisites, install instructions, blocks setup, then per-service usage sections.\n\n### API Reference (`v3/api-ref/`)\n\n**Auto-generated — do not edit directly.** Covers the Python SDK (`python/`), CLI commands (`cli/`), and REST API (`rest-api/`). CLI pages use `<ResponseField>` and `<Accordion>` components for arguments and options.\n\n### Release Notes (`v3/release-notes/`)\n\nChangelogs organized by product surface: `oss/` for open-source releases, `cloud/` for Prefect Cloud, `integrations/` for integration packages.\n\n### Contribute (`contribute/`)\n\nGuides for contributors: how to set up the dev environment, write docs, develop integrations, and follow code style conventions.\n\n## Adding vs. updating content\n\n### When to update an existing page vs. create a new one\n\n- **Update an existing page** when the new content is a variation, option, or closely related technique for something the page already covers. For example, a new retry strategy belongs on the existing retries page, not a new page.\n- **Create a new page** when the content addresses a distinct goal that doesn't fit naturally into any existing page. A good test: if the page title would need to become vague or a compound sentence to accommodate the new content, it deserves its own page.\n- When in doubt, prefer extending an existing page. Fewer, more comprehensive pages are easier for readers to discover than many small, fragmented ones.\n\n### When to add a new category or section\n\n- **Create a new subdirectory** only when you have multiple pages (or a clear roadmap for multiple pages) that share a theme not covered by any existing category. A single page does not justify a new category — place it in the closest existing one.\n- Before creating a category, check whether the content fits in an existing one. For example, a guide about running flows on a new cloud platform belongs in `deployment_infra/`, not a new category named after that platform.\n- New categories must also be added as a group in the `navigation.tabs` section of `docs/docs.json`, with an `index.mdx` page for the group overview.\n\n## Page templates\n\nStarter templates live in this skill directory. Copy one as the basis for a new page and fill in the bracketed placeholders:\n\n- **How-to guide** — `template-howto.mdx`\n- **Concept page** — `template-concept.mdx`\n\nAdjust headings and sections to fit the content — the templates show the expected shape, not a rigid format.\n\n### Keywords for searchability\n\nEvery page should include a `keywords` array in its frontmatter. Keywords feed Mintlify's search index and help readers find pages using terms that don't appear in the title or description.\n\n```yaml\nkeywords: [\"retry\", \"retries\", \"error handling\", \"fault tolerance\"]\n```\n\n- Include 3-5 lowercase terms a reader might search for.\n- Use synonyms and shorthand readers would actually type (e.g., \"k8s\" is wrong in prose but useful as a keyword alongside \"Kubernetes\").\n- Don't repeat words already in `title` or `description` — those are indexed automatically.\n\n## Registering pages in navigation\n\nEvery new page must be added to `docs/docs.json` under `navigation.tabs` or it won't appear in the sidebar. Add the page path (without `.mdx`) to the appropriate group:\n\n```json\n{\n  \"tab\": \"How-to Guides\",\n  \"pages\": [\n    \"v3/how-to-guides/index\",\n    {\n      \"group\": \"Workflows\",\n      \"pages\": [\n        \"v3/how-to-guides/workflows/write-and-run\",\n        \"v3/how-to-guides/workflows/retries\"\n      ]\n    }\n  ]\n}\n```\n\n- Each tab has a `\"tab\"` display name and either `\"pages\"` or `\"groups\"`.\n- Groups can nest: a group's `\"pages\"` array can contain strings (page paths) or nested `{\"group\": ..., \"pages\": [...]}` objects.\n- Place new pages at a logical position within the existing group — typically at the end, unless ordering matters for the reader.\n\n## Mintlify components\n\nUse these components (not standard Markdown admonition syntax):\n\n```mdx\n<Note>Important information.</Note>\n<Warning>Caution about potential issues.</Warning>\n<Tip>Helpful suggestion.</Tip>\n<Info>Additional context.</Info>\n\n<Accordion title=\"Expandable section\">\n  Content hidden until clicked.\n</Accordion>\n\n<Tabs>\n  <Tab title=\"Option A\">Content for A</Tab>\n  <Tab title=\"Option B\">Content for B</Tab>\n</Tabs>\n\n<Steps>\n  <Step title=\"First step\">Instructions</Step>\n  <Step title=\"Second step\">Instructions</Step>\n</Steps>\n\n<CardGroup cols={3}>\n  <Card title=\"Title\" icon=\"icon\" href=\"/v3/path\">\n    Description text.\n  </Card>\n</CardGroup>\n\n<CodeGroup>\n```bash pip\npip install prefect\n```\n```bash uv\nuv pip install prefect\n```\n</CodeGroup>\n```\n\n## Reusable snippets\n\nSnippets live in `snippets/` and are imported with JSX:\n\n```mdx\nimport ComponentName from '/snippets/path.mdx'\n\n<ComponentName />\n```\n\nAlways check for an existing snippet before writing duplicate content. Key snippets to know about:\n\n- `snippets/installation.mdx` — Standard Prefect install instructions (used in `v3/get-started/install.mdx`). Use this instead of writing ad-hoc install blocks.\n- `snippets/resource-management/` — Consistent \"manage this resource via CLI / API / Terraform / Helm\" callouts. Import the relevant variant when documenting a Prefect resource.\n\n## Code blocks\n\nCode blocks support language hints, filenames, line highlighting, and expandable sections:\n\n````mdx\n```python my_flow.py\nfrom prefect import flow\n\n@flow\ndef hello():\n    print(\"Hello!\")\n```\n\n```bash {3} [expandable]\nprefect deploy --all\nprefect work-pool create my-pool --type process\nprefect worker start --pool my-pool\n```\n````\n\nMark code blocks that should **not** be tested with the comment `{/* pmd-metadata: notest */}` on the line before the code block.\n\nPrefer minimal, runnable snippets that produce a visible result (printed output, a return value, or a logged message). Avoid placeholder names like `foo`/`bar` in user-facing examples — use realistic names that reflect the domain (e.g., `process_order`, `customer_id`).\n\n## Code example testing\n\nPython code blocks in `.mdx` files are automatically extracted and executed as tests using [pytest-markdown-docs](https://github.com/modal-labs/pytest-markdown-docs). Tests run in CI against a live Prefect server and are parallelized with pytest-xdist (up to 6 workers). All test configuration — fixtures, skip lists, and injected globals — lives in `docs/conftest.py`.\n\n### How it works\n\nBy default, every fenced Python code block in an `.mdx` file is treated as an independent test. The plugin extracts the block, executes it, and fails if it raises an exception. Each block runs in its own namespace unless `continuation` is used (see below).\n\n### Running tests locally\n\nThere is no `just` command for markdown tests. Run them manually:\n\n```bash\n# Start a Prefect server in the background\nPREFECT_HOME=$(pwd) uv run prefect server start &\n\n# Run the markdown doc tests\nPREFECT_API_URL=\"http://127.0.0.1:4200/api\" uv run --group markdown-docs pytest docs/ -m markdown-docs\n```\n\n### pmd-metadata directives\n\nControl test behavior with `{/* pmd-metadata: <directive> */}` comments placed on the line immediately before a code fence.\n\n**`notest`** — Skip this code block entirely. Use when code is illustrative, incomplete, or requires setup that cannot be provided in the test environment.\n\n```mdx\n{/* pmd-metadata: notest */}\n```python\n# This block will not be tested\nprefect deploy --some-hypothetical-flag\n```\n```\n\n**`continuation`** — Share state (imports, variables, function definitions) from preceding code blocks on the same page. Without this, each block starts with a clean namespace. Use when a multi-step example is split across blocks for readability.\n\n```mdx\n```python\nfrom prefect import flow\n\n@flow\ndef my_workflow() -> str:\n    return \"Hello, world!\"\n```\n\n{/* pmd-metadata: continuation */}\n```python\nmy_workflow()  # Can reference the function defined above\n```\n```\n\n**`fixture:<name>`** — Inject a pytest fixture defined in `conftest.py` as a global in the code block. Use when a block needs mocking (e.g., HTTP calls).\n\n```mdx\n{/* pmd-metadata: fixture:mock_post_200 */}\n```python\nimport requests\nresponse = requests.post(endpoint, headers=headers, json=data)\nassert response.status_code == 200\n```\n```\n\n### Global imports\n\nThe `pytest_markdown_docs_globals` hook in `conftest.py` injects a small set of globals into every code block automatically: `Mapped`, `Run`, `Union`, `mapped_column`, `sa`. You do not need to import these in doc examples.\n\n### Autouse fixtures\n\nTwo fixtures are applied to every test automatically (defined in `conftest.py`):\n\n- `mock_runner_start` — Mocks `prefect.cli.flow.Runner.start` so flow-serving examples don't actually start a long-running process.\n- `mock_base_worker_submit` — Mocks `BaseWorker.submit` and `KubernetesWorker.submit` so worker examples don't attempt real infrastructure calls.\n\n### Skipped files\n\nSome files are skipped entirely via the `SKIP_FILES` dict in `conftest.py`. Common reasons include needing database fixtures, block cleanup, live network calls, or async contexts. Additionally:\n\n- All files under `v3/api-ref/python/` are auto-skipped (generated reference docs).\n- All files under `v3/examples/` are auto-skipped (tested separately in their source repo).\n\nWhen adding a new page that genuinely cannot be tested, add it to `SKIP_FILES` with a reason rather than marking every block with `notest`.\n\n## Images\n\nPlace images in `v3/img/` organized by section (e.g., `v3/img/ui/`, `v3/img/concepts/`). Reference them with absolute paths:\n\n```mdx\n![Description](/v3/img/ui/screenshot.png)\n```\n\n- Always include meaningful alt text that describes what the image shows.\n- Use compressed PNG or WebP format to keep page load times fast.\n- Avoid committing unnecessarily large screenshots; crop to the relevant area.\n\n## Linting\n\nDocs are linted with [Vale](https://vale.sh/) using Google style, Vale defaults, and custom Prefect rules. Run locally:\n\n```bash\njust lint\n```\n\nOr manually: `vale --glob='**/*.{md,mdx}' .`\n\n## Tone and style\n\n- Use second person (\"you\") and active voice in present tense.\n- Avoid first person (\"I\", \"we\") and marketing language (\"powerful\", \"seamless\", \"best-in-class\").\n- Be direct and concise. Shorter sentences are easier to scan.\n- Follow the [Google developer documentation style guide](https://developers.google.com/style) as the baseline.\n\nExamples of preferred phrasing:\n\n| Instead of | Write |\n|---|---|\n| \"We recommend configuring...\" | \"Configure...\" |\n| \"You'll want to make sure to...\" | \"Make sure to...\" or just state the instruction |\n| \"This powerful feature allows you to...\" | \"Use [feature] to...\" |\n| \"I'll show you how to set up...\" | \"To set up..., do the following:\" |\n| \"It should be noted that...\" | State the fact directly |\n| \"In order to\" | \"To\" |\n\nWhen introducing a concept, lead with what the reader can *do*, not what the feature *is*:\n\n- Before: \"The retry mechanism is a configurable system that allows flows to recover from transient failures.\"\n- After: \"Add retries to your flow to recover automatically from transient failures.\"\n\n## Quality checklist\n\nBefore considering a page complete, verify:\n\n1. The page opens with appropriate context: for how-to guides, a single-sentence scope line (or jump straight into steps if the title already establishes the goal); for concepts and advanced pages, an opening paragraph that defines the topic and why it matters.\n2. Prerequisites (tools, access, prior knowledge) are called out up front.\n3. The page includes at least one cross-link to a related Concept or How-to page.\n4. All code blocks are runnable and tested, or explicitly marked with `{/* pmd-metadata: notest */}` with a reason.\n5. Frontmatter includes `keywords` with 3-5 search terms not already in the title or description.\n6. The page is registered in `docs/docs.json` navigation.\n\n## Common mistakes\n\n- Using `#` (H1) in the body — the frontmatter `title` already renders as H1.\n- Using relative links or including `.mdx` in link paths.\n- Using Markdown admonitions (`> **Note:**`) instead of Mintlify components (`<Note>`).\n- Inconsistent heading hierarchy (jumping from H2 to H4).\n- Missing `description` or `keywords` in frontmatter — both improve search discoverability.\n- First-person pronouns (\"I\", \"we\") — use \"you\" or imperative voice.\n- Wrong terminology casing: \"Prefect cloud\" (should be \"Prefect Cloud\"), \"Prefect Server\" (should be \"Prefect server\"), \"k8s\" (should be \"Kubernetes\"), \"infra\" (should be \"infrastructure\").\n- Forgetting to register a new page in `docs/docs.json` — the page won't appear in nav.\n- Forgetting to add a redirect in `docs/docs.json` when moving or renaming a page.\n- Overusing `<Note>`/`<Tip>`/`<Warning>` — reserve for genuinely important callouts, not every paragraph.\n\n<!-- File: .claude/skills/write-docs/template-concept.mdx (Tokens: ~197 | Category: claude-rule) -->\n---\ntitle: [Concept name]\ndescription: [One sentence explaining what this concept does.]\nkeywords: [\"keyword1\", \"keyword2\", \"keyword3\"]\n---\n\n{/*\n  keywords: Include 3-5 lowercase terms a reader might search for.\n  Use synonyms and abbreviations readers would type — e.g., for a\n  flows page: [\"flow\", \"workflow\", \"orchestration\", \"decorator\"].\n  Don't repeat words already in the title or description.\n*/}\n\n```python\nfrom prefect import flow\n\n@flow\ndef my_flow():\n    return \"Hello!\"\n\nmy_flow()\n```\n\n## What is [concept]?\n\nExplain the concept and why it matters.\n\n## [Key aspect or behavior]\n\nDeeper explanation with examples.\n\n<Tip>\nCall out a key detail the reader should remember.\n</Tip>\n\n## Next steps\n\n- [How to do X with this concept](/v3/how-to-guides/category/guide)\n\n<!-- File: .claude/skills/write-docs/template-howto.mdx (Tokens: ~300 | Category: claude-rule) -->\n# Claude Directive: template-howto.mdx\n\nPath: `.claude/skills/write-docs/template-howto.mdx`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/PrefectHQ/prefect/HEAD/.claude/skills/write-docs/template-howto.mdx)\n\n<!-- File: .claude/commands/repro.md (Tokens: ~314 | Category: command-prompt) -->\n---\ndescription: Reproduce a bug in the Prefect codebase.\nargument-hint: \"[the gh issue link or issue number]\"\n---\n\nuse `gh` to read and understand the following github issue: $1.\n\nRead the body and all comments in the issue.\n\nbefore reproducing, `rg` for documentation in `docs/` that may be relevant to the issue.\n\nif a `repros/` directory already exists (it will be locally gitignored), `rg` for relevant SDK usage to gain context.\n\n\nTo reproduce, create a file named by issue number (ie. `1234.py`) in a locally gitignored (.git/info/exclude) `repros/` directory with a minimal reproducible example that reproduces the issue. Because `repros/` is gitignored, you should NEVER reference it in a PR body, instead put the entire reproduction script in a python snippet inside a `<details>` tag.\n\nIf the reproduction requires external dependencies, use `uv` to inline script dependencies to install them like this:\n\n```\n# ///script\n# dependencies = [\"pandas\", \"numpy\"]\n# ///\n\n# rest of script\n```\nand then invoke the script with `uv run --with-editable . repros/1234.py` to use the editable copy of Prefect along with the external dependencies.\n\nReview the actual `prefect` library in `src/prefect` (or integration in `src/integrations`) to ensure that the reproduction is aware of the implementation details of the code.\n</yakaai_skills>"}