{"owner":"facebook","repo":"relay","hasSkills":true,"totalSkillsCount":54,"totalTokensCount":21532,"categories":["anthropic-skill","command-prompt","plugin-manifest"],"hasMcp":false,"mcpConfig":null,"found":["skills/relay-performance/SKILL.md","packages/babel-plugin-relay/package.json","packages/relay-e2e-test/.llms/skills/relay-e2e-test/SKILL.md",".claude/commands/fix-ci.md","skills/relay-best-practices/SKILL.md","packages/eslint-plugin-relay-internal/README.md","packages/eslint-plugin-relay-internal/package.json","packages/react-relay/README.md","packages/react-relay/package.json","packages/relay-compiler/package.json","packages/babel-plugin-relay/README.md","packages/relay-compiler/README.md","packages/relay-e2e-test/README.md","packages/relay-e2e-test/package.json","packages/relay-e2e-test/tsconfig.json","packages/relay-e2e-test/tsconfig.template.json","packages/relay-runtime/README.md","packages/relay-runtime/package.json","packages/relay-runtime/tsconfig.json","packages/relay-test-utils-internal/README.md","packages/relay-test-utils-internal/package.json","packages/relay-test-utils/README.md","packages/relay-test-utils/package.json","packages/relay-e2e-test/fixtures/data-driven-dependencies/module.md","packages/relay-e2e-test/fixtures/data-driven-dependencies/module.snap.md","packages/relay-e2e-test/fixtures/mixed-interface/nested-field.md","packages/relay-e2e-test/fixtures/mixed-interface/nested-field.snap.md","packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.md","packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.snap.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.snap.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.snap.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.snap.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.snap.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.snap.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.snap.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.snap.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.snap.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction.md","packages/relay-e2e-test/fixtures/mutations/useMutationAction.snap.md","packages/relay-e2e-test/fixtures/queries/greeting.md","packages/relay-e2e-test/fixtures/queries/greeting.snap.md","packages/relay-e2e-test/fixtures/typechecking/unselected-field.md","packages/relay-e2e-test/fixtures/typechecking/unselected-field.snap.md","packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-github.md","packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-internal.md","packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/writing-fixtures.md"],"skills":{"skills/relay-performance/SKILL.md":"---\nname: relay-performance\ndescription: >-\n  Performance best practices for Relay applications. Use when optimizing data\n  fetching, reducing re-renders, configuring caching, or improving time to first\n  meaningful paint. Covers query placement, @defer, pagination, fetch policies,\n  garbage collection, fragment granularity, and server-side filtering. Companion\n  to the relay-best-practices skill which covers correctness and architecture.\n---\n\n# Relay Performance Best Practices\n\nPerformance-focused guidance for Relay applications. For correctness, naming,\nand architectural patterns, see the `relay-best-practices` skill.\n\nFor detailed API documentation, read the relevant page from `<llm-docs>/`\n(available in `node_modules/relay-runtime/llm-docs/` after v20.1.1).\n\n## One Query Per Screen\n\nEach screen or route should have **one** (or very few) root queries. Relay\ncoalesces all fragment data needs into a single network request per query.\nMultiple root queries on the same screen defeat this optimization — the browser\nmakes multiple parallel requests that each carry redundant overhead (HTTP\nheaders, connection setup, response parsing).\n\n```\nGOOD:                              BAD:\nRoute → 1 query                    Route → 3 queries\n  ├─ Header (fragment)               ├─ Header (query #1)\n  ├─ Content (fragment)               ├─ Content (query #2)\n  └─ Sidebar (fragment)               └─ Sidebar (query #3)\n```\n\n## Preload Before Rendering the Root\n\nFetch the initial query **before** calling `createRoot().render()`. This\noverlaps the network request with React's initialization, minimizing time to\nfirst meaningful paint.\n\n```tsx\n// Start fetch immediately — before React even initializes\nconst queryRef = loadQuery(environment, AppQuery, initialVariables);\n\n// Then render — data may already be available\nconst root = createRoot(document.getElementById('root'));\nroot.render(\n  <RelayEnvironmentProvider environment={environment}>\n    <Suspense fallback={<AppSkeleton />}>\n      <App queryRef={queryRef} />\n    </Suspense>\n  </RelayEnvironmentProvider>\n);\n```\n\n## Use `@defer` for Non-Critical Content\n\nDefer secondary or below-the-fold content so primary UI renders faster.\nRelay streams deferred data progressively via Suspense — the initial response\narrives smaller and the critical path renders sooner.\n\n```graphql\nquery ProfileScreenQuery($id: ID!) {\n  user(id: $id) {\n    ...ProfileHeader_user\n    ...ProfileDetails_user @defer\n    ...ProfileComments_user @defer\n  }\n}\n```\n\n```tsx\nfunction ProfileScreen({ queryRef }) {\n  const data = usePreloadedQuery(ProfileScreenQuery, queryRef);\n\n  return (\n    <ScrollView>\n      <ProfileHeader user={data.user} />\n      <Suspense fallback={<DetailsSkeleton />}>\n        <ProfileDetails user={data.user} />\n      </Suspense>\n      <Suspense fallback={<CommentsSkeleton />}>\n        <ProfileComments user={data.user} />\n      </Suspense>\n    </ScrollView>\n  );\n}\n```\n\nGood candidates for `@defer`:\n- Sidebar content\n- Below-the-fold sections\n- Tabs and accordions not visible on initial load\n- Heavy item details in paginated lists\n\n## Fetch Policies\n\n`store-or-network` (the default) is correct for most cases — it reuses cached\ndata and only hits the network for missing or stale data.\n\n| Policy | When to use |\n|--------|-------------|\n| `store-or-network` | Default. Best balance of speed and freshness. |\n| `store-and-network` | Show cached data immediately, update in background. |\n| `network-only` | Freshness is critical (e.g., after a mutation with wide side effects). |\n| `store-only` | Offline-first or reading data already guaranteed to be in the store. |\n\nReserve `network-only` for rare cases. Overusing it turns Relay into a\nno-cache client and eliminates the benefit of the normalized store.\n\n## Configure Garbage Collection\n\nSet `gcReleaseBufferSize` on the Relay Store to retain recently-used queries\nafter their components unmount. The default is 10. This makes navigating back\nto a previously visited screen instant (data is still in the store) instead of\ntriggering a new network request.\n\n```tsx\nconst store = new Store(new RecordSource(), {\n  gcReleaseBufferSize: 20,\n});\n```\n\nFor apps with many screens or heavy navigation, increase the buffer. For\nmemory-constrained environments (mobile), keep it conservative.\n\n## Filter and Sort on the Server\n\nUse GraphQL field arguments to filter and sort data on the server rather than\nfetching everything and processing in JavaScript.\n\n```tsx\n// BAD: fetch all tasks, filter on client\nconst data = useFragment(graphql`\n  fragment TaskList_user on User {\n    tasks { id, title, status }\n  }\n`, user);\nconst active = data.tasks.filter(t => t.status === 'ACTIVE');\n\n// GOOD: filter on server via field argument\nconst data = useFragment(graphql`\n  fragment TaskList_user on User {\n    tasks(status: ACTIVE) { id, title }\n  }\n`, user);\n```\n\nServer-side filtering reduces payload size, avoids unnecessary network\ntransfer, and reduces memory usage on the client.\n\n## Never Fetch Unbounded Collections\n\nAlways paginate list fields using `@connection` + `usePaginationFragment`.\nFetching an entire collection at once risks transferring megabytes of data,\nstalling the UI during normalization, and exhausting device memory.\n\nStart with a page size appropriate for the viewport (e.g., 10–20 items) and\nload more on scroll.\n\n```graphql\n# BAD: fetches every item — unbounded\nfragment NotificationList_user on User {\n  notifications {\n    id\n    message\n  }\n}\n\n# GOOD: paginated with a bounded first page\nfragment NotificationList_user on User\n  @argumentDefinitions(\n    count: { type: \"Int\", defaultValue: 10 }\n    cursor: { type: \"String\" }\n  )\n  @refetchable(queryName: \"NotificationListPaginationQuery\") {\n  notifications(first: $count, after: $cursor)\n    @connection(key: \"NotificationList_notifications\") {\n    edges {\n      node {\n        id\n        message\n      }\n    }\n  }\n}\n```\n\n## Keep Fragments Granular\n\nSplit large fragments into smaller, component-scoped fragments so Relay can\nre-render **only** the components whose data actually changed. A single\nmonolithic fragment shared by many components causes all of them to re-render\nwhen any field in the fragment changes.\n\n```tsx\n// BAD: one large fragment, all children re-render on any field change\nfunction PostCard({ post }) {\n  const data = useFragment(graphql`\n    fragment PostCard_post on Post {\n      title\n      body\n      author { name, profilePicture { uri } }\n      likeCount\n      commentCount\n    }\n  `, post);\n  return (\n    <>\n      <PostHeader title={data.title} author={data.author} />\n      <PostBody body={data.body} />\n      <PostFooter likes={data.likeCount} comments={data.commentCount} />\n    </>\n  );\n}\n\n// GOOD: each child owns its fragment, re-renders independently\nfunction PostHeader({ post }: { post: PostHeader_post$key }) {\n  const data = useFragment(graphql`\n    fragment PostHeader_post on Post {\n      title\n      author { name }\n    }\n  `, post);\n  // Only re-renders when title or author.name changes\n}\n\nfunction PostFooter({ post }: { post: PostFooter_post$key }) {\n  const data = useFragment(graphql`\n    fragment PostFooter_post on Post {\n      likeCount\n      commentCount\n    }\n  `, post);\n  // Only re-renders when like/comment counts change\n}\n```\n\n## One Connection Per Component\n\nUse a single `usePaginationFragment` per component. Multiple connections in\none component make pagination state harder to reason about — cursor tracking,\nloading states, and `hasNext` flags become tangled. Split each connection into\nits own component instead.\n\n## Avoid Unnecessary Refetches\n\nAfter a mutation, let Relay's normalized store auto-update components by\nspreading relevant fragments in the mutation response. Do not call `refetch()`\nor `fetchQuery()` when the store update is sufficient.\n\n```graphql\n# GOOD: updated data comes back with the mutation response\nmutation UpdateUserMutation($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    user {\n      ...UserProfile_user\n      ...UserAvatar_user\n    }\n  }\n}\n\n# BAD: requires a separate round-trip after mutation\nmutation UpdateUserMutation($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    user { id }\n  }\n}\n```\n\nUse `fetchKey` sparingly — changing it forces a full network round trip.\nReserve `refetchQueries` / manual refetch for cases where the mutation's side\neffects are too broad to capture in the response payload.\n\n## Fetch Only What You Need\n\nEach fragment should request only the fields the component actually renders.\nDo not add fields \"just in case\" — unused fields increase payload size and slow\ndown parsing and normalization. Relay's `unused-fields` lint rule catches this.\n\nIf a child component needs more data, add a fragment **to the child** and\nspread it in the parent — do not widen the parent's fragment.\n","packages/babel-plugin-relay/package.json":"{\n  \"name\": \"babel-plugin-relay\",\n  \"description\": \"A Babel Plugin for use with Relay applications.\",\n  \"version\": \"21.0.1\",\n  \"keywords\": [\n    \"graphql\",\n    \"relay\",\n    \"babel\",\n    \"babel-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/babel-plugin-relay\"\n  },\n  \"dependencies\": {\n    \"babel-plugin-macros\": \"^2.0.0\",\n    \"cosmiconfig\": \"^5.0.5\",\n    \"graphql\": \"17.0.2\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.25.2\",\n    \"prettier\": \"3.9.4\"\n  },\n  \"resolutions\": {\n    \"@babel/traverse\": \"^7.23.2\"\n  }\n}\n","packages/relay-e2e-test/.llms/skills/relay-e2e-test/SKILL.md":"---\nname: relay-e2e-test\ndescription: Write and run markdown-driven e2e tests for Relay. Covers fixture format, server/client code patterns, interaction DSL, snapshots, and running tests.\nallowed-tools: Bash, Read, Edit, Write, AskUserQuestion, mcp__plugin_meta_mux__search_files\nmetadata:\n  oncalls: ['relay']\n  strict: true\n---\n\n# Relay E2E Tests\n\nMarkdown-driven end-to-end tests for Relay. Each test is a self-contained `.md` file that defines a GraphQL server (via [Grats](https://grats.capt.dev/)), a Relay-powered React component, and optional interaction steps. The test harness extracts the code blocks, compiles them with Grats + relay-compiler, renders with React Testing Library, runs interactions, and snapshot-tests the output.\n\nTests run against **Relay runtime packages from source**, so changes are reflected immediately without a build step.\n\n## References\n\nRead the appropriate reference file based on your task:\n\n- **[Writing fixtures](references/writing-fixtures.md)** — fixture format, example, server/client code patterns, interaction DSL, snapshots. Read when creating or modifying test fixtures.\n- **[Running tests (internal)](references/running-tests-internal.md)** — setup, commands, and compiler resolution for fbsource / OD. Read when running tests internally.\n- **[Running tests (GitHub)](references/running-tests-github.md)** — setup, commands, and compiler resolution for the OSS repo. Read when running tests on GitHub.\n",".claude/commands/fix-ci.md":"# Fix CI Skill\n\nYou are a specialized skill for checking GitHub CI status and fixing failing tests in the Relay project.\n\n## Your Task\n\n1. **Check Current CI Status**\n   - Use `gh run list --branch=main --workflow=ci.yml --limit 5` to see recent workflow runs\n   - If the most recent run is failing, use `gh run view <ID>` using the ID from the most recent run to get detailed status\n   - Identify any failing jobs or checks\n\n2. **Analyze Failures**\n   - For each failing job, use `gh run view <run-id> --log-failed` to get failure logs\n   - **Note**: If this command has no output, you may need to upgrade `gh`. See https://github.com/cli/cli/issues/10551.\n   - Parse the logs to identify the specific test failures or errors\n\n3. **Fix the Issues**\n   - Based on the failure type, take appropriate action:\n   - See `CONTRIBUTING.md` for instructions on how to work in this repository.\n\n   ### Special Case: Out-of-date Cargo.lock\n\n   If the failure is related to an out-of-date `Cargo.lock` file (look for errors like \"the lock file needs to be updated but --locked was passed\" or diffs showing changes to Cargo.lock), it cannot be fixed in this repository.\n\n   `compiler/Cargo.lock` is generated from Meta's internal monorepo and synced here, so a pull request editing it would be overwritten by the next sync.\n\n   1. **Report it**: Tell the user the lock file is stale and needs to be regenerated internally, then landed — it syncs here automatically afterwards.\n\n   2. **Do NOT manually update Cargo.lock**, and do not open a pull request against it.\n\n4. **Create a Pull Request**\n   - Create a new branch: `git checkout -b fix-ci-failures-$(date +%Y%m%d-%H%M%S)`\n   - Stage all changes: `git add .`\n   - Commit with descriptive message about what was fixed\n   - Push the branch: `git push -u origin HEAD`\n   - Create PR using `gh pr create` with:\n     - **IMPORTANT: Always include `--label \"Fix CI Skill\"` in the `gh pr create` command**\n     - Title: \"Fix CI failures - [Brief description]\"\n     - Body: Detailed explanation of:\n       - Which jobs were failing\n       - What the errors were\n       - How you fixed them\n       - Test results showing the fixes work\n\n5. **Monitor PR and Iterate Until Passing**\n   - After creating the PR, monitor the CI status in a loop\n   - Use `gh run list --branch=<your-branch> --limit 1` to check the latest run\n   - Use `gh run view <run-id>` to check if it's completed and its status\n   - If the run is still in progress, wait 30 seconds and check again\n   - If the run fails:\n     - Use `gh run view <run-id> --log-failed` to get failure logs\n     - Analyze the new failures (they may be different from the original ones)\n     - Fix the issues following the same process as step 3\n     - Commit and push the fixes: `git add . && git commit -m \"Fix additional CI failures\" && git push`\n     - Continue monitoring the new CI run\n   - Keep iterating until all CI checks pass\n   - Report success when all checks are green\n\n## Important Guidelines\n\n- Always verify fixes locally before creating a PR\n- If you can't automatically fix an issue, document it clearly in your response\n- Check if there are multiple failures - fix all of them in one PR if possible\n- Run the relevant test suite locally before pushing\n- Make sure your fixes don't introduce new issues\n- If CI is passing, report that and don't create unnecessary PRs\n\n## Example Workflow\n\n```bash\n# 1. Check CI status\ngh run list --branch=main --workflow=ci.yml --limit 5\n\n# 2. Get details of latest run\ngh run view 20949129659 --log-failed\n\n# 3. If JS tests are failing, run locally\nyarn run jest <failing-test>\n\n# 4. Fix the code\n# (Read files, make edits)\n\n# 5. Verify fix\nyarn run jest <failing-test>\n\n# 6. Create PR\ngit checkout -b fix-ci-failures-20260106\ngit add .\ngit commit -m \"Fix failing jest tests in MockPayloadGenerator\"\ngit push -u origin HEAD\ngh pr create --label \"Fix CI Skill\" --title \"Fix CI: MockPayloadGenerator test failures\" --body \"...\"\n```\n\n## Start Here\n\nBegin by checking the current CI status and reporting what you find.\n","skills/relay-best-practices/SKILL.md":"---\nname: relay-best-practices\ndescription: >-\n  Best practices for writing idiomatic Relay code. ALWAYS use this skill when\n  writing or modifying React components that use Relay for data fetching. Covers\n  fragments, queries, mutations, pagination, and common anti-patterns. Use when\n  you see `useFragment`, `useLazyLoadQuery`, `usePreloadedQuery`, `useMutation`,\n  `usePaginationFragment`, `graphql` template literals, `react-relay` imports,\n  or `__generated__/*.graphql` files. Also use when asked to explain Relay\n  concepts, debug Relay issues, or review Relay code.\n---\n\n# Relay Best Practices\n\nRelay is a GraphQL client for React that enforces colocated, composable, and\ntype-safe data fetching. Its core insight is that each component should declare\nexactly what data it needs via GraphQL fragments, and Relay handles the rest —\nfetching, caching, consistency, and updates.\n\nThis skill provides opinionated guidance on which patterns to prefer. For\ndetailed API documentation, read the relevant page from the doc map below.\n\n## Documentation\n\nRelay ships LLM-friendly docs in `node_modules/relay-runtime/llm-docs/`\n(available after v20.1.1). For older versions, fetch the same files from\n`https://raw.githubusercontent.com/facebook/relay/main/website/docs/`.\n\nPaths below are relative to this directory (`<llm-docs>/`). Read the relevant\npage before writing Relay code. Key docs:\n\n| Topic | Path |\n|-------|------|\n| Core concepts & philosophy | `principles-and-architecture/thinking-in-relay.mdx` |\n| Fragments | `guided-tour/rendering/fragments.mdx` |\n| Queries | `guided-tour/rendering/queries.mdx` |\n| Mutations | `guided-tour/updating-data/graphql-mutations.mdx` |\n| Pagination | `guided-tour/list-data/pagination.mdx` |\n| Refetching | `guided-tour/refetching/refetching-queries-with-different-data.mdx` |\n| `useFragment` | `api-reference/hooks/use-fragment.mdx` |\n| `usePreloadedQuery` | `api-reference/hooks/use-preloaded-query.mdx` |\n| `useQueryLoader` / `loadQuery` | `api-reference/hooks/load-query.mdx` |\n| `useMutation` | `api-reference/hooks/use-mutation.mdx` |\n| `usePaginationFragment` | `api-reference/hooks/use-pagination-fragment.mdx` |\n| `@throwOnFieldError` | `guides/throw-on-field-error-directive.mdx` |\n| `@catch` directive | `guides/catch-directive.mdx` |\n| Semantic nullability | `guides/semantic-nullability.mdx` |\n| Relay Resolvers | `guides/relay-resolvers/introduction.mdx` |\n| Testing | `guides/testing-relay-components.mdx` |\n| Compiler setup | `getting-started/compiler.mdx` |\n| Compiler configuration | `getting-started/compiler-config.mdx` |\n| Lint rules (ESLint plugin) | `getting-started/lint-rules.mdx` |\n\n**For performance-specific guidance** (query placement, `@defer`, pagination,\nfetch policies, caching, fragment granularity), see the companion\n`relay-performance` skill.\n\n## Core Philosophy\n\nThese principles are the foundation of every decision below. When in doubt,\nrefer back to them.\n\n- **Co-location**: Each component declares its own data requirements via a\n  GraphQL fragment, right next to the rendering code. Data needs travel with the\n  component, not separately.\n- **Data masking**: A component can only access the fields it explicitly\n  selected in its own fragment. Parents cannot see child fragment data, and vice\n  versa. This prevents implicit coupling between components.\n- **Composition**: Fragments compose into parent fragments and ultimately into\n  queries, forming a tree that mirrors the component tree. The compiler flattens\n  this into a single network request per query.\n- **Render-as-you-fetch**: Start fetching data before the component that needs\n  it renders. This avoids sequential request waterfalls.\n- **Normalized store**: Relay maintains a flat, ID-keyed cache. When a mutation\n  returns updated data, every component reading that data re-renders\n  automatically. You do not need to manually propagate changes.\n\n## Compiler Workflow\n\nRelay uses an ahead-of-time compiler that reads `graphql` tagged template\nliterals in your code and generates runtime artifacts and TypeScript/Flow types.\n\n### Finding the config\n\nThe compiler looks for its config in these locations (checked in order):\n- `relay.config.{json,js,mjs,ts}` in the project root\n- A `\"relay\"` key in `package.json`\n\nSee `<llm-docs>/getting-started/compiler-config.mdx` for the full config schema.\nYou can also emit a JSON Schema for the config by running\n`npx relay-compiler config-json-schema`.\n\n### Running the compiler\n\nRun `npx relay-compiler` after any change to the contents of a `graphql` tagged\ntemplate literal or the docblock of a Relay Resolver. Some projects add this as\na script in `package.json` (e.g., `yarn relay`). The compiler also supports watch mode (`--watch`), but avoid using it in\nnon-interactive contexts since the process never exits.\n\nGenerated files go into `__generated__/` directories next to the source files.\nNever edit these files — they are overwritten on every compiler run. If you see\ntype errors about missing generated types, run the compiler first — the\ntypes are likely just out of date.\n\n## Lint Rules\n\nRelay's ESLint plugin (`eslint-plugin-relay`) is a key part of the developer\nexperience. Two rules are especially important:\n\n- `relay/unused-fields` — detects GraphQL fields that are selected in a\n  fragment but never read in the component. This prevents the \"append-only\n  query\" problem where fragments accumulate unused fields over time, fetching\n  data no component actually needs.\n- `relay/no-future-added-value` — prevents explicitly handling the\n  `\"%future added value\"` enum placeholder that Relay inserts to ensure you\n  handle the possibility of new enum variants being added by the server.\n\nSee `<llm-docs>/getting-started/lint-rules.mdx` for installation and configuration.\n\n## Decision Rules\n\n### Queries belong at roots — never in hooks\n\nQueries belong at **route entrypoints** (the top-level component for a URL).\nHooks are leaves — reused across many components. A query inside a hook fires\nlate (after the hook's host renders) AND duplicates across every caller. The fix\nis always: accept a fragment key as a parameter, use `useFragment`.\n\nUse `usePreloadedQuery` + `useQueryLoader` (or `loadQuery`). Start the fetch in\nan event handler, route transition, or during app initialization — before the\ncomponent renders. `useLazyLoadQuery` does not start fetching until render,\ncreating waterfalls. See `<llm-docs>/guided-tour/rendering/queries.mdx` for the full pattern.\n\n### Before fixing where a query lives, ask if it should exist\n\n| Question | If YES |\n|----------|--------|\n| Parent already fetches this GraphQL type? | Delete query, use `useFragment` |\n| Component only fetches and passes data down? | Delete the wrapper component entirely (loader anti-pattern) |\n| Query is inside a custom hook? | Delete query, accept a fragment key param |\n| Two components fetch the same data? | Delete one query, fetch in a common ancestor |\n| Data is only used for logging/analytics? | Move to `@defer` or server-side logging |\n| Data is static config (same for every user)? | Inject server-side, no round-trip needed |\n\n### `loadQuery` in `useEffect` is worse than `useLazyLoadQuery`\n\n`useEffect` runs **after paint**, so the fetch starts even later than\n`useLazyLoadQuery` (which at least starts during render). Call `loadQuery` in\nevent handlers, route transitions, or app initialization — never in effects.\n\n### Walking the ancestor tree for `useFragment`\n\nWhen deciding whether `useFragment` can replace a query, walk **up** the\ncomponent tree from your component. Stop at: route boundaries, feature gates,\nconditional renders, or user-triggered interactions. Keep walking through:\nunconditional renders, layout/wrapper components, context providers.\n\nIf any ancestor already queries the GraphQL type you need, `useFragment` is\nthe answer. Threading fragment keys through several layers of props is fine —\nit IS the correct pattern.\n\n### Don't default query variables to empty values\n\nNever default a query variable to `''`, `0`, or `null` when the real value is\nunavailable. This fires the query with bad data, returning wrong results or\nerrors. Instead, use conditional rendering (`if (!id) return null`) or\n`@include`/`@skip` directives to omit the field entirely.\n\n### Data flow: Always use fragments\n\nEvery component that displays server data should declare a fragment and receive\na fragment reference (the `$key` type) as a prop. The parent spreads the\nchild's fragment in its own query or fragment and passes the result down. See\nthe \"Maintain fragment co-location\" anti-pattern below for an example.\n\n### Mutations: Spread fragments into responses\n\nSpread the consuming component's fragment into the mutation response rather than\nselecting fields individually. This keeps them in sync automatically. See the\nanti-pattern example below.\n\n### Error handling: Use `@throwOnFieldError` and `@catch`\n\nThe recommended approach for handling field errors and nullability is to add\n`@throwOnFieldError` to your fragment or query. This causes Relay to throw a\nJavaScript exception if a field error is encountered, which can be caught by a\nReact error boundary. It also enables non-null types for `@semanticNonNull`\nfields, eliminating unnecessary null checks. Note that this pattern depends on\nReact error boundaries being configured in your application — proceed with\ncaution if error boundaries are not set up robustly.\n\nFor fields where you want to handle errors locally instead of throwing, use\n`@catch` to receive errors inline as `{ ok: true, value: T } | { ok: false,\nerrors: [...] }`.\n\n`@required` is also available for declaring that specific fields must be\nnon-null, but `@throwOnFieldError` + `@catch` is the preferred pattern for new\ncode.\n\nSee `<llm-docs>/guides/throw-on-field-error-directive.mdx`, `<llm-docs>/guides/catch-directive.mdx`,\nand `<llm-docs>/guides/semantic-nullability.mdx`.\n\n### Pagination: Use the three-directive pattern\n\nAlways use `@argumentDefinitions` (for cursor/count variables),\n`@refetchable` (to auto-generate the pagination query), and `@connection` (to\nidentify the connection for store management) together. Never write manual\npagination queries. See `<llm-docs>/guided-tour/list-data/pagination.mdx`.\n\n### Client state: Prefer Relay Resolvers\n\nWhen multiple components need to read client-side data, use Relay Resolvers to\ndefine client-only fields on the GraphQL schema rather than prop-drilling or\nReact context. This gives client state the same composability and caching\nguarantees as server data. Use `useClientQuery` for queries that read only\nresolver-defined fields.\n\nSee `<llm-docs>/guides/relay-resolvers/introduction.mdx` for how to define resolvers.\n\n## Critical Anti-Patterns\n\n### Never copy Relay data into React state\n\nThis is the single most important rule. Do not read data from `useFragment` and\ncopy it into `useState`, and do not update that state manually in mutation\n`onCompleted` callbacks.\n\n```tsx\n// WRONG: Copying Relay data into React state\nfunction UserProfile({userKey}) {\n  const data = useFragment(UserProfileFragment, userKey);\n  const [name, setName] = useState(data.name); // broken\n\n  const [commit] = useMutation(UpdateNameMutation);\n  const handleSave = (newName) => {\n    commit({\n      variables: {name: newName},\n      onCompleted: (response) => {\n        setName(response.updateName.user.name); // broken\n      },\n    });\n  };\n  return <span>{name}</span>;\n}\n```\n\nWhy this is wrong: Relay's normalized store is the single source of truth. When\na mutation returns updated data with a matching `id`, Relay automatically\nupdates every component reading that data via `useFragment`. By copying into\n`useState`, you create a second source of truth that Relay cannot update. The\ncomponent will show stale data whenever the record is updated by another\nmutation, subscription, or refetch elsewhere in the app.\n\n```tsx\n// CORRECT: Read directly from the fragment\nfunction UserProfile({userKey}) {\n  const data = useFragment(UserProfileFragment, userKey);\n  const [commit, isInFlight] = useMutation(UpdateNameMutation);\n\n  const handleSave = (newName) => {\n    commit({variables: {name: newName}});\n    // No onCompleted needed — Relay updates the store automatically,\n    // and useFragment re-renders this component with the new data.\n  };\n  return <span>{data.name}</span>;\n}\n```\n\nSimilarly, do not store a fragment key (the `$key` prop) in React state. Relay\ngarbage collects data that is no longer retained by a mounted query component —\nif the component that originally fetched the data unmounts, a stashed key may\npoint to data that is no longer in the store.\n\n### Maintain fragment co-location\n\nDo not fetch all data in a parent's query and pass raw data objects as props to\nchildren. This defeats data masking and creates tight coupling — adding a field\nto a child component requires editing the parent's query. Note that the\n`relay/unused-fields` lint rule will flag fields selected in the parent that\nare only used by children — this is a good signal that you need to extract a\nfragment.\n\n```tsx\n// WRONG: Parent fetches everything, passes raw data\nfunction Parent({queryRef}) {\n  const data = usePreloadedQuery(graphql`\n    query ParentQuery {\n      user {\n        name\n        email\n        avatarUrl\n      }\n    }\n  `, queryRef);\n  return <UserCard name={data.user.name} avatarUrl={data.user.avatarUrl} />;\n}\n\n// CORRECT: Child declares its own fragment\nfunction Parent({queryRef}) {\n  const data = usePreloadedQuery(graphql`\n    query ParentQuery {\n      user {\n        ...UserCard_user\n      }\n    }\n  `, queryRef);\n  return <UserCard user={data.user} />;\n}\n```\n\n### Spread fragments into mutation responses\n\nDo not select fields individually in both a fragment and a mutation response —\nthey will drift out of sync. Spread the fragment instead:\n\n```graphql\n# WRONG\nmutation UpdateUserMutation($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    user { id, name, email, avatarUrl }\n  }\n}\n\n# CORRECT\nmutation UpdateUserMutation($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    user { ...UserCard_user }\n  }\n}\n```\n\n## Correctness\n\n### Use `optimisticUpdater` for store-dependent values\n\nIf an optimistic value depends on current store state (e.g., incrementing a\nlike count), use `optimisticUpdater` instead of `optimisticResponse`. Multiple\noverlapping optimistic responses can compound incorrectly — two simultaneous\n\"like\" mutations both read count=5 and set count=6, instead of 5→6→7. When one\nrolls back, the store is left in an inconsistent state.\n\n### Invalidate data after wide-effect mutations\n\nWhen a mutation has side effects too broad to capture in a single response\npayload, use `invalidateRecord()` for targeted invalidation or\n`invalidateStore()` for global invalidation. Pair with\n`useSubscribeToInvalidationState` on mounted components to trigger refetches\nfor stale data automatically.\n\n### Handle staleness explicitly\n\nRelay treats cached data as fresh **indefinitely** by default. Two approaches:\n\n- **Time-based**: Set `queryCacheExpirationTime` on the Relay Store to\n  automatically mark data stale after a duration.\n- **Event-based**: Call `invalidateRecord()` after mutations whose side effects\n  extend beyond the mutation response payload.\n\nWithout explicit staleness handling, components can display arbitrarily old data\nafter the user returns to a previously visited screen.\n\n### Single artifact directory for type safety\n\nWithout setting `artifactDirectory` in the compiler config, fragment references\nmay default to `any`, losing type safety. Set it and align your bundler's\nmodule resolution accordingly. See `<llm-docs>/getting-started/compiler-config.mdx`.\n\n### Use `@updatable` for store manipulation\n\nPrefer typesafe updatable queries/fragments over raw store manipulation with\nstring-based field access (e.g., `store.get(id).setValue(newName, 'name')`).\nUpdatable fragments provide getters and setters, reducing the risk of typos\nand type mismatches.\n\n### Avoid unnecessary refetches after mutations\n\nDo not call `refetch()` or `fetchQuery()` after mutations when spreading\ncomponent fragments in the mutation response would auto-update the store. Each\nunnecessary refetch is a wasted network request and delays the UI update.\n\nReserve manual refetches for cases where the mutation's side effects are too\nbroad to capture in the response payload — and in those cases, prefer\n`invalidateRecord()` (see above).\n\n### Use subscriptions for real-time data\n\nPrefer GraphQL Subscriptions over polling (`setInterval` + `fetchQuery`) or\nmanual refresh buttons for data that must stay current. Subscriptions push\nupdates only when data changes and integrate with Relay's normalized store\nautomatically.\n\n## Naming Conventions\n\nRelay **enforces** that operation names match the module (file) they are defined\nin. Mismatched names cause compiler errors, not just style warnings.\n\n| Element | Convention | Example |\n|---------|-----------|---------|\n| Fragment | `ComponentName_propName` | `UserCard_user` |\n| Query | `ComponentNameQuery` | `HomePageQuery` |\n| Mutation | `ComponentNameMutation` | `LikeButtonMutation` |\n| Generated files | `__generated__/*.graphql` | Never edit these |\n\nThe module name is the filename stripped of all extensions (`.react.js`, `.tsx`,\netc.). `UserCard.react.js` → module name `UserCard`.\n\n### Renaming operations when extracting to a new file\n\nWhen moving a component to a new file, rename only the operations **defined in\nthat file** to match the new filename. Do NOT rename fragment spreads that\nreference fragments owned by other modules — those names belong to their\ndefining component.\n\nRenaming an operation also changes its generated type name (e.g.,\n`UserCard_user$key` → `ProfileCard_user$key`), so update all downstream imports\nof those generated types.\n\n### Never hand-edit `__generated__/` files\n\nThe next compiler run overwrites any manual edits. If you see type errors about\nmissing generated types, run the compiler first — the types are just out of\ndate, not missing.\n\n### Verify mutation variable keys after auto-formatting\n\nAuto-formatters and linters can rename variables in ways that silently break\nmutation calls. After running lint auto-fix, verify that variable keys in\n`commit({ variables: { ... } })` still match the generated `Mutation$variables`\ntype (check for `data` vs `input` mismatches in particular).\n","packages/eslint-plugin-relay-internal/README.md":"# eslint-plugin-relay-internal\n\nESLint rules intended to run on Relay's own codebase.\n","packages/eslint-plugin-relay-internal/package.json":"{\n  \"name\": \"eslint-plugin-relay-internal\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"description\": \"ESLint rules intended to run on Relay's own codebase\",\n  \"keywords\": [\n    \"eslint\",\n    \"eslintplugin\",\n    \"eslint-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/relay-test-utils-internal\"\n  },\n  \"main\": \"./lib/index.js\",\n  \"exports\": \"./lib/index.js\",\n  \"dependencies\": {},\n  \"engines\": {\n    \"node\": \"^14.17.0 || ^16.0.0 || >= 18.0.0\"\n  },\n  \"peerDependencies\": {\n    \"eslint\": \">=7\"\n  }\n}\n","packages/react-relay/README.md":"## React APIs for Relay\n\nThis package contains a collection of React APIs: Hooks and Components that are\nintegrated with Relay runtime.\n\nExample:\n\n```js\n// @flow\n\nimport type {UserComponent_user$key} from 'UserComponent_user.graphql';\n\nconst React = require('react');\n\nconst {graphql, useFragment} = require('react-relay');\n\ntype Props = {\n  user: UserComponent_user$key,\n};\n\nfunction UserComponent(props: Props) {\n  const data = useFragment(\n    graphql`\n      fragment UserComponent_user on User {\n        name\n        profile_picture(scale: 2) {\n          uri\n        }\n      }\n    `,\n    props.user,\n  );\n\n  return (\n    <>\n      <h1>{data.name}</h1>\n      <div>\n        <img src={data.profile_picture?.uri} />\n      </div>\n    </>\n  );\n}\n```\n\nFor complete API reference, visit https://relay.dev/.\n","packages/react-relay/package.json":"{\n  \"name\": \"react-relay\",\n  \"description\": \"A framework for building GraphQL-driven React applications.\",\n  \"version\": \"21.0.1\",\n  \"keywords\": [\n    \"graphql\",\n    \"relay\",\n    \"react\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/react-relay\"\n  },\n  \"dependencies\": {\n    \"@babel/runtime\": \"^7.25.0\",\n    \"fbjs\": \"^3.0.2\",\n    \"invariant\": \"^2.2.4\",\n    \"nullthrows\": \"^1.1.1\",\n    \"relay-runtime\": \"21.0.1\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.9.0 || ^17 || ^18 || ^19\"\n  },\n  \"directories\": {\n    \"\": \"./\"\n  },\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"haste_commonjs\": true\n}\n","packages/relay-compiler/package.json":"{\n  \"name\": \"relay-compiler\",\n  \"description\": \"A compiler tool for building GraphQL-driven applications.\",\n  \"version\": \"21.0.1\",\n  \"keywords\": [\n    \"graphql\",\n    \"relay\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/relay-compiler\"\n  },\n  \"main\": \"index.js\",\n  \"bin\": \"cli.js\"\n}\n","packages/babel-plugin-relay/README.md":"## babel-plugin-relay\n\nRelay requires a Babel plugin to convert GraphQL tags to runtime artifacts.\n\nA _very_ simplified example of what this plugin is doing:\n\n```js\n// It converts this code\nconst fragment = graphql`\n  fragment User_fragment on User {\n    name\n  }\n`;\n\n// To require generated ASTs for fragments and queries\nconst fragment = require('__generated__/User_fragment.graphql');\n```\n\n## Plugin Configuration\n\n`babel-plugin-relay` will discover the config if:\n\n- There is a `relay.config.json`, `relay.config.js` file at the root of the\n  project (i.e. in the same folder as the `package.json` file).\n- The `package.json` file contains a `\"relay\"` key.\n\n> [!IMPORTANT]\n> This Babel plugin does not support `relay.config.mjs` or `package.json` with `\"type\": \"module\"`.\n\n### Supported configuration options for `babel-plugin-relay`\n\n- `artifactDirectory` A specific directory to output all artifacts to. When\n  enabling this the babel plugin needs `artifactDirectory` to be set as well.\n  [string]\n- `eagerEsModules` This option enables emitting ES modules artifacts.\n  [boolean][default: false]\n- `codegenCommand` The command to run to compile Relay files. [string]\n- `isDevVariableName` Name of the global variable for dev mode (e.g. `__DEV__`).\n  [string]\n- `jsModuleFormat` Formatting style for generated files. `commonjs` or `haste`.\n  Default is `commonjs`. [string]\n\n[Configuration Instructions](https://relay.dev/docs/getting-started/installation-and-setup/#set-up-babel-plugin-relay)\n","packages/relay-compiler/README.md":"# Relay Compiler\n\nSee https://relay.dev/docs/next/guides/compiler/\n","packages/relay-e2e-test/README.md":"# relay-e2e-test Documentation\n\nPath: `packages/relay-e2e-test/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/README.md)","packages/relay-e2e-test/package.json":"# Relay-e2e-test Skill\n\nPath: `packages/relay-e2e-test/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/package.json)","packages/relay-e2e-test/tsconfig.json":"# Relay-e2e-test Skill\n\nPath: `packages/relay-e2e-test/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/tsconfig.json)","packages/relay-e2e-test/tsconfig.template.json":"# Relay-e2e-test Skill\n\nPath: `packages/relay-e2e-test/tsconfig.template.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/tsconfig.template.json)","packages/relay-runtime/README.md":"# relay-runtime Documentation\n\nPath: `packages/relay-runtime/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-runtime/README.md)","packages/relay-runtime/package.json":"# Relay-runtime Skill\n\nPath: `packages/relay-runtime/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-runtime/package.json)","packages/relay-runtime/tsconfig.json":"# Relay-runtime Skill\n\nPath: `packages/relay-runtime/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-runtime/tsconfig.json)","packages/relay-test-utils-internal/README.md":"# relay-test-utils-internal Documentation\n\nPath: `packages/relay-test-utils-internal/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils-internal/README.md)","packages/relay-test-utils-internal/package.json":"# Relay-test-utils-internal Skill\n\nPath: `packages/relay-test-utils-internal/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils-internal/package.json)","packages/relay-test-utils/README.md":"# relay-test-utils Documentation\n\nPath: `packages/relay-test-utils/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils/README.md)","packages/relay-test-utils/package.json":"# Relay-test-utils Skill\n\nPath: `packages/relay-test-utils/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils/package.json)","packages/relay-e2e-test/fixtures/data-driven-dependencies/module.md":"# Data-driven-dependencies Skill\n\nPath: `packages/relay-e2e-test/fixtures/data-driven-dependencies/module.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/data-driven-dependencies/module.md)","packages/relay-e2e-test/fixtures/data-driven-dependencies/module.snap.md":"# Data-driven-dependencies Skill\n\nPath: `packages/relay-e2e-test/fixtures/data-driven-dependencies/module.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/data-driven-dependencies/module.snap.md)","packages/relay-e2e-test/fixtures/mixed-interface/nested-field.md":"# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/nested-field.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/nested-field.md)","packages/relay-e2e-test/fixtures/mixed-interface/nested-field.snap.md":"# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/nested-field.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/nested-field.snap.md)","packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.md":"# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.md)","packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.snap.md":"# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction.snap.md)","packages/relay-e2e-test/fixtures/queries/greeting.md":"# Queries Skill\n\nPath: `packages/relay-e2e-test/fixtures/queries/greeting.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/queries/greeting.md)","packages/relay-e2e-test/fixtures/queries/greeting.snap.md":"# Queries Skill\n\nPath: `packages/relay-e2e-test/fixtures/queries/greeting.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/queries/greeting.snap.md)","packages/relay-e2e-test/fixtures/typechecking/unselected-field.md":"# Typechecking Skill\n\nPath: `packages/relay-e2e-test/fixtures/typechecking/unselected-field.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/typechecking/unselected-field.md)","packages/relay-e2e-test/fixtures/typechecking/unselected-field.snap.md":"# Typechecking Skill\n\nPath: `packages/relay-e2e-test/fixtures/typechecking/unselected-field.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/typechecking/unselected-field.snap.md)","packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-github.md":"# References Skill\n\nPath: `packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-github.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-github.md)","packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-internal.md":"# References Skill\n\nPath: `packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-internal.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-internal.md)","packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/writing-fixtures.md":"# References Skill\n\nPath: `packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/writing-fixtures.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/writing-fixtures.md)"},"files":{"skills/relay-performance/SKILL.md":"---\nname: relay-performance\ndescription: >-\n  Performance best practices for Relay applications. Use when optimizing data\n  fetching, reducing re-renders, configuring caching, or improving time to first\n  meaningful paint. Covers query placement, @defer, pagination, fetch policies,\n  garbage collection, fragment granularity, and server-side filtering. Companion\n  to the relay-best-practices skill which covers correctness and architecture.\n---\n\n# Relay Performance Best Practices\n\nPerformance-focused guidance for Relay applications. For correctness, naming,\nand architectural patterns, see the `relay-best-practices` skill.\n\nFor detailed API documentation, read the relevant page from `<llm-docs>/`\n(available in `node_modules/relay-runtime/llm-docs/` after v20.1.1).\n\n## One Query Per Screen\n\nEach screen or route should have **one** (or very few) root queries. Relay\ncoalesces all fragment data needs into a single network request per query.\nMultiple root queries on the same screen defeat this optimization — the browser\nmakes multiple parallel requests that each carry redundant overhead (HTTP\nheaders, connection setup, response parsing).\n\n```\nGOOD:                              BAD:\nRoute → 1 query                    Route → 3 queries\n  ├─ Header (fragment)               ├─ Header (query #1)\n  ├─ Content (fragment)               ├─ Content (query #2)\n  └─ Sidebar (fragment)               └─ Sidebar (query #3)\n```\n\n## Preload Before Rendering the Root\n\nFetch the initial query **before** calling `createRoot().render()`. This\noverlaps the network request with React's initialization, minimizing time to\nfirst meaningful paint.\n\n```tsx\n// Start fetch immediately — before React even initializes\nconst queryRef = loadQuery(environment, AppQuery, initialVariables);\n\n// Then render — data may already be available\nconst root = createRoot(document.getElementById('root'));\nroot.render(\n  <RelayEnvironmentProvider environment={environment}>\n    <Suspense fallback={<AppSkeleton />}>\n      <App queryRef={queryRef} />\n    </Suspense>\n  </RelayEnvironmentProvider>\n);\n```\n\n## Use `@defer` for Non-Critical Content\n\nDefer secondary or below-the-fold content so primary UI renders faster.\nRelay streams deferred data progressively via Suspense — the initial response\narrives smaller and the critical path renders sooner.\n\n```graphql\nquery ProfileScreenQuery($id: ID!) {\n  user(id: $id) {\n    ...ProfileHeader_user\n    ...ProfileDetails_user @defer\n    ...ProfileComments_user @defer\n  }\n}\n```\n\n```tsx\nfunction ProfileScreen({ queryRef }) {\n  const data = usePreloadedQuery(ProfileScreenQuery, queryRef);\n\n  return (\n    <ScrollView>\n      <ProfileHeader user={data.user} />\n      <Suspense fallback={<DetailsSkeleton />}>\n        <ProfileDetails user={data.user} />\n      </Suspense>\n      <Suspense fallback={<CommentsSkeleton />}>\n        <ProfileComments user={data.user} />\n      </Suspense>\n    </ScrollView>\n  );\n}\n```\n\nGood candidates for `@defer`:\n- Sidebar content\n- Below-the-fold sections\n- Tabs and accordions not visible on initial load\n- Heavy item details in paginated lists\n\n## Fetch Policies\n\n`store-or-network` (the default) is correct for most cases — it reuses cached\ndata and only hits the network for missing or stale data.\n\n| Policy | When to use |\n|--------|-------------|\n| `store-or-network` | Default. Best balance of speed and freshness. |\n| `store-and-network` | Show cached data immediately, update in background. |\n| `network-only` | Freshness is critical (e.g., after a mutation with wide side effects). |\n| `store-only` | Offline-first or reading data already guaranteed to be in the store. |\n\nReserve `network-only` for rare cases. Overusing it turns Relay into a\nno-cache client and eliminates the benefit of the normalized store.\n\n## Configure Garbage Collection\n\nSet `gcReleaseBufferSize` on the Relay Store to retain recently-used queries\nafter their components unmount. The default is 10. This makes navigating back\nto a previously visited screen instant (data is still in the store) instead of\ntriggering a new network request.\n\n```tsx\nconst store = new Store(new RecordSource(), {\n  gcReleaseBufferSize: 20,\n});\n```\n\nFor apps with many screens or heavy navigation, increase the buffer. For\nmemory-constrained environments (mobile), keep it conservative.\n\n## Filter and Sort on the Server\n\nUse GraphQL field arguments to filter and sort data on the server rather than\nfetching everything and processing in JavaScript.\n\n```tsx\n// BAD: fetch all tasks, filter on client\nconst data = useFragment(graphql`\n  fragment TaskList_user on User {\n    tasks { id, title, status }\n  }\n`, user);\nconst active = data.tasks.filter(t => t.status === 'ACTIVE');\n\n// GOOD: filter on server via field argument\nconst data = useFragment(graphql`\n  fragment TaskList_user on User {\n    tasks(status: ACTIVE) { id, title }\n  }\n`, user);\n```\n\nServer-side filtering reduces payload size, avoids unnecessary network\ntransfer, and reduces memory usage on the client.\n\n## Never Fetch Unbounded Collections\n\nAlways paginate list fields using `@connection` + `usePaginationFragment`.\nFetching an entire collection at once risks transferring megabytes of data,\nstalling the UI during normalization, and exhausting device memory.\n\nStart with a page size appropriate for the viewport (e.g., 10–20 items) and\nload more on scroll.\n\n```graphql\n# BAD: fetches every item — unbounded\nfragment NotificationList_user on User {\n  notifications {\n    id\n    message\n  }\n}\n\n# GOOD: paginated with a bounded first page\nfragment NotificationList_user on User\n  @argumentDefinitions(\n    count: { type: \"Int\", defaultValue: 10 }\n    cursor: { type: \"String\" }\n  )\n  @refetchable(queryName: \"NotificationListPaginationQuery\") {\n  notifications(first: $count, after: $cursor)\n    @connection(key: \"NotificationList_notifications\") {\n    edges {\n      node {\n        id\n        message\n      }\n    }\n  }\n}\n```\n\n## Keep Fragments Granular\n\nSplit large fragments into smaller, component-scoped fragments so Relay can\nre-render **only** the components whose data actually changed. A single\nmonolithic fragment shared by many components causes all of them to re-render\nwhen any field in the fragment changes.\n\n```tsx\n// BAD: one large fragment, all children re-render on any field change\nfunction PostCard({ post }) {\n  const data = useFragment(graphql`\n    fragment PostCard_post on Post {\n      title\n      body\n      author { name, profilePicture { uri } }\n      likeCount\n      commentCount\n    }\n  `, post);\n  return (\n    <>\n      <PostHeader title={data.title} author={data.author} />\n      <PostBody body={data.body} />\n      <PostFooter likes={data.likeCount} comments={data.commentCount} />\n    </>\n  );\n}\n\n// GOOD: each child owns its fragment, re-renders independently\nfunction PostHeader({ post }: { post: PostHeader_post$key }) {\n  const data = useFragment(graphql`\n    fragment PostHeader_post on Post {\n      title\n      author { name }\n    }\n  `, post);\n  // Only re-renders when title or author.name changes\n}\n\nfunction PostFooter({ post }: { post: PostFooter_post$key }) {\n  const data = useFragment(graphql`\n    fragment PostFooter_post on Post {\n      likeCount\n      commentCount\n    }\n  `, post);\n  // Only re-renders when like/comment counts change\n}\n```\n\n## One Connection Per Component\n\nUse a single `usePaginationFragment` per component. Multiple connections in\none component make pagination state harder to reason about — cursor tracking,\nloading states, and `hasNext` flags become tangled. Split each connection into\nits own component instead.\n\n## Avoid Unnecessary Refetches\n\nAfter a mutation, let Relay's normalized store auto-update components by\nspreading relevant fragments in the mutation response. Do not call `refetch()`\nor `fetchQuery()` when the store update is sufficient.\n\n```graphql\n# GOOD: updated data comes back with the mutation response\nmutation UpdateUserMutation($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    user {\n      ...UserProfile_user\n      ...UserAvatar_user\n    }\n  }\n}\n\n# BAD: requires a separate round-trip after mutation\nmutation UpdateUserMutation($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    user { id }\n  }\n}\n```\n\nUse `fetchKey` sparingly — changing it forces a full network round trip.\nReserve `refetchQueries` / manual refetch for cases where the mutation's side\neffects are too broad to capture in the response payload.\n\n## Fetch Only What You Need\n\nEach fragment should request only the fields the component actually renders.\nDo not add fields \"just in case\" — unused fields increase payload size and slow\ndown parsing and normalization. Relay's `unused-fields` lint rule catches this.\n\nIf a child component needs more data, add a fragment **to the child** and\nspread it in the parent — do not widen the parent's fragment.\n","packages/babel-plugin-relay/package.json":"{\n  \"name\": \"babel-plugin-relay\",\n  \"description\": \"A Babel Plugin for use with Relay applications.\",\n  \"version\": \"21.0.1\",\n  \"keywords\": [\n    \"graphql\",\n    \"relay\",\n    \"babel\",\n    \"babel-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/babel-plugin-relay\"\n  },\n  \"dependencies\": {\n    \"babel-plugin-macros\": \"^2.0.0\",\n    \"cosmiconfig\": \"^5.0.5\",\n    \"graphql\": \"17.0.2\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.25.2\",\n    \"prettier\": \"3.9.4\"\n  },\n  \"resolutions\": {\n    \"@babel/traverse\": \"^7.23.2\"\n  }\n}\n","packages/relay-e2e-test/.llms/skills/relay-e2e-test/SKILL.md":"---\nname: relay-e2e-test\ndescription: Write and run markdown-driven e2e tests for Relay. Covers fixture format, server/client code patterns, interaction DSL, snapshots, and running tests.\nallowed-tools: Bash, Read, Edit, Write, AskUserQuestion, mcp__plugin_meta_mux__search_files\nmetadata:\n  oncalls: ['relay']\n  strict: true\n---\n\n# Relay E2E Tests\n\nMarkdown-driven end-to-end tests for Relay. Each test is a self-contained `.md` file that defines a GraphQL server (via [Grats](https://grats.capt.dev/)), a Relay-powered React component, and optional interaction steps. The test harness extracts the code blocks, compiles them with Grats + relay-compiler, renders with React Testing Library, runs interactions, and snapshot-tests the output.\n\nTests run against **Relay runtime packages from source**, so changes are reflected immediately without a build step.\n\n## References\n\nRead the appropriate reference file based on your task:\n\n- **[Writing fixtures](references/writing-fixtures.md)** — fixture format, example, server/client code patterns, interaction DSL, snapshots. Read when creating or modifying test fixtures.\n- **[Running tests (internal)](references/running-tests-internal.md)** — setup, commands, and compiler resolution for fbsource / OD. Read when running tests internally.\n- **[Running tests (GitHub)](references/running-tests-github.md)** — setup, commands, and compiler resolution for the OSS repo. Read when running tests on GitHub.\n",".claude/commands/fix-ci.md":"# Fix CI Skill\n\nYou are a specialized skill for checking GitHub CI status and fixing failing tests in the Relay project.\n\n## Your Task\n\n1. **Check Current CI Status**\n   - Use `gh run list --branch=main --workflow=ci.yml --limit 5` to see recent workflow runs\n   - If the most recent run is failing, use `gh run view <ID>` using the ID from the most recent run to get detailed status\n   - Identify any failing jobs or checks\n\n2. **Analyze Failures**\n   - For each failing job, use `gh run view <run-id> --log-failed` to get failure logs\n   - **Note**: If this command has no output, you may need to upgrade `gh`. See https://github.com/cli/cli/issues/10551.\n   - Parse the logs to identify the specific test failures or errors\n\n3. **Fix the Issues**\n   - Based on the failure type, take appropriate action:\n   - See `CONTRIBUTING.md` for instructions on how to work in this repository.\n\n   ### Special Case: Out-of-date Cargo.lock\n\n   If the failure is related to an out-of-date `Cargo.lock` file (look for errors like \"the lock file needs to be updated but --locked was passed\" or diffs showing changes to Cargo.lock), it cannot be fixed in this repository.\n\n   `compiler/Cargo.lock` is generated from Meta's internal monorepo and synced here, so a pull request editing it would be overwritten by the next sync.\n\n   1. **Report it**: Tell the user the lock file is stale and needs to be regenerated internally, then landed — it syncs here automatically afterwards.\n\n   2. **Do NOT manually update Cargo.lock**, and do not open a pull request against it.\n\n4. **Create a Pull Request**\n   - Create a new branch: `git checkout -b fix-ci-failures-$(date +%Y%m%d-%H%M%S)`\n   - Stage all changes: `git add .`\n   - Commit with descriptive message about what was fixed\n   - Push the branch: `git push -u origin HEAD`\n   - Create PR using `gh pr create` with:\n     - **IMPORTANT: Always include `--label \"Fix CI Skill\"` in the `gh pr create` command**\n     - Title: \"Fix CI failures - [Brief description]\"\n     - Body: Detailed explanation of:\n       - Which jobs were failing\n       - What the errors were\n       - How you fixed them\n       - Test results showing the fixes work\n\n5. **Monitor PR and Iterate Until Passing**\n   - After creating the PR, monitor the CI status in a loop\n   - Use `gh run list --branch=<your-branch> --limit 1` to check the latest run\n   - Use `gh run view <run-id>` to check if it's completed and its status\n   - If the run is still in progress, wait 30 seconds and check again\n   - If the run fails:\n     - Use `gh run view <run-id> --log-failed` to get failure logs\n     - Analyze the new failures (they may be different from the original ones)\n     - Fix the issues following the same process as step 3\n     - Commit and push the fixes: `git add . && git commit -m \"Fix additional CI failures\" && git push`\n     - Continue monitoring the new CI run\n   - Keep iterating until all CI checks pass\n   - Report success when all checks are green\n\n## Important Guidelines\n\n- Always verify fixes locally before creating a PR\n- If you can't automatically fix an issue, document it clearly in your response\n- Check if there are multiple failures - fix all of them in one PR if possible\n- Run the relevant test suite locally before pushing\n- Make sure your fixes don't introduce new issues\n- If CI is passing, report that and don't create unnecessary PRs\n\n## Example Workflow\n\n```bash\n# 1. Check CI status\ngh run list --branch=main --workflow=ci.yml --limit 5\n\n# 2. Get details of latest run\ngh run view 20949129659 --log-failed\n\n# 3. If JS tests are failing, run locally\nyarn run jest <failing-test>\n\n# 4. Fix the code\n# (Read files, make edits)\n\n# 5. Verify fix\nyarn run jest <failing-test>\n\n# 6. Create PR\ngit checkout -b fix-ci-failures-20260106\ngit add .\ngit commit -m \"Fix failing jest tests in MockPayloadGenerator\"\ngit push -u origin HEAD\ngh pr create --label \"Fix CI Skill\" --title \"Fix CI: MockPayloadGenerator test failures\" --body \"...\"\n```\n\n## Start Here\n\nBegin by checking the current CI status and reporting what you find.\n","skills/relay-best-practices/SKILL.md":"---\nname: relay-best-practices\ndescription: >-\n  Best practices for writing idiomatic Relay code. ALWAYS use this skill when\n  writing or modifying React components that use Relay for data fetching. Covers\n  fragments, queries, mutations, pagination, and common anti-patterns. Use when\n  you see `useFragment`, `useLazyLoadQuery`, `usePreloadedQuery`, `useMutation`,\n  `usePaginationFragment`, `graphql` template literals, `react-relay` imports,\n  or `__generated__/*.graphql` files. Also use when asked to explain Relay\n  concepts, debug Relay issues, or review Relay code.\n---\n\n# Relay Best Practices\n\nRelay is a GraphQL client for React that enforces colocated, composable, and\ntype-safe data fetching. Its core insight is that each component should declare\nexactly what data it needs via GraphQL fragments, and Relay handles the rest —\nfetching, caching, consistency, and updates.\n\nThis skill provides opinionated guidance on which patterns to prefer. For\ndetailed API documentation, read the relevant page from the doc map below.\n\n## Documentation\n\nRelay ships LLM-friendly docs in `node_modules/relay-runtime/llm-docs/`\n(available after v20.1.1). For older versions, fetch the same files from\n`https://raw.githubusercontent.com/facebook/relay/main/website/docs/`.\n\nPaths below are relative to this directory (`<llm-docs>/`). Read the relevant\npage before writing Relay code. Key docs:\n\n| Topic | Path |\n|-------|------|\n| Core concepts & philosophy | `principles-and-architecture/thinking-in-relay.mdx` |\n| Fragments | `guided-tour/rendering/fragments.mdx` |\n| Queries | `guided-tour/rendering/queries.mdx` |\n| Mutations | `guided-tour/updating-data/graphql-mutations.mdx` |\n| Pagination | `guided-tour/list-data/pagination.mdx` |\n| Refetching | `guided-tour/refetching/refetching-queries-with-different-data.mdx` |\n| `useFragment` | `api-reference/hooks/use-fragment.mdx` |\n| `usePreloadedQuery` | `api-reference/hooks/use-preloaded-query.mdx` |\n| `useQueryLoader` / `loadQuery` | `api-reference/hooks/load-query.mdx` |\n| `useMutation` | `api-reference/hooks/use-mutation.mdx` |\n| `usePaginationFragment` | `api-reference/hooks/use-pagination-fragment.mdx` |\n| `@throwOnFieldError` | `guides/throw-on-field-error-directive.mdx` |\n| `@catch` directive | `guides/catch-directive.mdx` |\n| Semantic nullability | `guides/semantic-nullability.mdx` |\n| Relay Resolvers | `guides/relay-resolvers/introduction.mdx` |\n| Testing | `guides/testing-relay-components.mdx` |\n| Compiler setup | `getting-started/compiler.mdx` |\n| Compiler configuration | `getting-started/compiler-config.mdx` |\n| Lint rules (ESLint plugin) | `getting-started/lint-rules.mdx` |\n\n**For performance-specific guidance** (query placement, `@defer`, pagination,\nfetch policies, caching, fragment granularity), see the companion\n`relay-performance` skill.\n\n## Core Philosophy\n\nThese principles are the foundation of every decision below. When in doubt,\nrefer back to them.\n\n- **Co-location**: Each component declares its own data requirements via a\n  GraphQL fragment, right next to the rendering code. Data needs travel with the\n  component, not separately.\n- **Data masking**: A component can only access the fields it explicitly\n  selected in its own fragment. Parents cannot see child fragment data, and vice\n  versa. This prevents implicit coupling between components.\n- **Composition**: Fragments compose into parent fragments and ultimately into\n  queries, forming a tree that mirrors the component tree. The compiler flattens\n  this into a single network request per query.\n- **Render-as-you-fetch**: Start fetching data before the component that needs\n  it renders. This avoids sequential request waterfalls.\n- **Normalized store**: Relay maintains a flat, ID-keyed cache. When a mutation\n  returns updated data, every component reading that data re-renders\n  automatically. You do not need to manually propagate changes.\n\n## Compiler Workflow\n\nRelay uses an ahead-of-time compiler that reads `graphql` tagged template\nliterals in your code and generates runtime artifacts and TypeScript/Flow types.\n\n### Finding the config\n\nThe compiler looks for its config in these locations (checked in order):\n- `relay.config.{json,js,mjs,ts}` in the project root\n- A `\"relay\"` key in `package.json`\n\nSee `<llm-docs>/getting-started/compiler-config.mdx` for the full config schema.\nYou can also emit a JSON Schema for the config by running\n`npx relay-compiler config-json-schema`.\n\n### Running the compiler\n\nRun `npx relay-compiler` after any change to the contents of a `graphql` tagged\ntemplate literal or the docblock of a Relay Resolver. Some projects add this as\na script in `package.json` (e.g., `yarn relay`). The compiler also supports watch mode (`--watch`), but avoid using it in\nnon-interactive contexts since the process never exits.\n\nGenerated files go into `__generated__/` directories next to the source files.\nNever edit these files — they are overwritten on every compiler run. If you see\ntype errors about missing generated types, run the compiler first — the\ntypes are likely just out of date.\n\n## Lint Rules\n\nRelay's ESLint plugin (`eslint-plugin-relay`) is a key part of the developer\nexperience. Two rules are especially important:\n\n- `relay/unused-fields` — detects GraphQL fields that are selected in a\n  fragment but never read in the component. This prevents the \"append-only\n  query\" problem where fragments accumulate unused fields over time, fetching\n  data no component actually needs.\n- `relay/no-future-added-value` — prevents explicitly handling the\n  `\"%future added value\"` enum placeholder that Relay inserts to ensure you\n  handle the possibility of new enum variants being added by the server.\n\nSee `<llm-docs>/getting-started/lint-rules.mdx` for installation and configuration.\n\n## Decision Rules\n\n### Queries belong at roots — never in hooks\n\nQueries belong at **route entrypoints** (the top-level component for a URL).\nHooks are leaves — reused across many components. A query inside a hook fires\nlate (after the hook's host renders) AND duplicates across every caller. The fix\nis always: accept a fragment key as a parameter, use `useFragment`.\n\nUse `usePreloadedQuery` + `useQueryLoader` (or `loadQuery`). Start the fetch in\nan event handler, route transition, or during app initialization — before the\ncomponent renders. `useLazyLoadQuery` does not start fetching until render,\ncreating waterfalls. See `<llm-docs>/guided-tour/rendering/queries.mdx` for the full pattern.\n\n### Before fixing where a query lives, ask if it should exist\n\n| Question | If YES |\n|----------|--------|\n| Parent already fetches this GraphQL type? | Delete query, use `useFragment` |\n| Component only fetches and passes data down? | Delete the wrapper component entirely (loader anti-pattern) |\n| Query is inside a custom hook? | Delete query, accept a fragment key param |\n| Two components fetch the same data? | Delete one query, fetch in a common ancestor |\n| Data is only used for logging/analytics? | Move to `@defer` or server-side logging |\n| Data is static config (same for every user)? | Inject server-side, no round-trip needed |\n\n### `loadQuery` in `useEffect` is worse than `useLazyLoadQuery`\n\n`useEffect` runs **after paint**, so the fetch starts even later than\n`useLazyLoadQuery` (which at least starts during render). Call `loadQuery` in\nevent handlers, route transitions, or app initialization — never in effects.\n\n### Walking the ancestor tree for `useFragment`\n\nWhen deciding whether `useFragment` can replace a query, walk **up** the\ncomponent tree from your component. Stop at: route boundaries, feature gates,\nconditional renders, or user-triggered interactions. Keep walking through:\nunconditional renders, layout/wrapper components, context providers.\n\nIf any ancestor already queries the GraphQL type you need, `useFragment` is\nthe answer. Threading fragment keys through several layers of props is fine —\nit IS the correct pattern.\n\n### Don't default query variables to empty values\n\nNever default a query variable to `''`, `0`, or `null` when the real value is\nunavailable. This fires the query with bad data, returning wrong results or\nerrors. Instead, use conditional rendering (`if (!id) return null`) or\n`@include`/`@skip` directives to omit the field entirely.\n\n### Data flow: Always use fragments\n\nEvery component that displays server data should declare a fragment and receive\na fragment reference (the `$key` type) as a prop. The parent spreads the\nchild's fragment in its own query or fragment and passes the result down. See\nthe \"Maintain fragment co-location\" anti-pattern below for an example.\n\n### Mutations: Spread fragments into responses\n\nSpread the consuming component's fragment into the mutation response rather than\nselecting fields individually. This keeps them in sync automatically. See the\nanti-pattern example below.\n\n### Error handling: Use `@throwOnFieldError` and `@catch`\n\nThe recommended approach for handling field errors and nullability is to add\n`@throwOnFieldError` to your fragment or query. This causes Relay to throw a\nJavaScript exception if a field error is encountered, which can be caught by a\nReact error boundary. It also enables non-null types for `@semanticNonNull`\nfields, eliminating unnecessary null checks. Note that this pattern depends on\nReact error boundaries being configured in your application — proceed with\ncaution if error boundaries are not set up robustly.\n\nFor fields where you want to handle errors locally instead of throwing, use\n`@catch` to receive errors inline as `{ ok: true, value: T } | { ok: false,\nerrors: [...] }`.\n\n`@required` is also available for declaring that specific fields must be\nnon-null, but `@throwOnFieldError` + `@catch` is the preferred pattern for new\ncode.\n\nSee `<llm-docs>/guides/throw-on-field-error-directive.mdx`, `<llm-docs>/guides/catch-directive.mdx`,\nand `<llm-docs>/guides/semantic-nullability.mdx`.\n\n### Pagination: Use the three-directive pattern\n\nAlways use `@argumentDefinitions` (for cursor/count variables),\n`@refetchable` (to auto-generate the pagination query), and `@connection` (to\nidentify the connection for store management) together. Never write manual\npagination queries. See `<llm-docs>/guided-tour/list-data/pagination.mdx`.\n\n### Client state: Prefer Relay Resolvers\n\nWhen multiple components need to read client-side data, use Relay Resolvers to\ndefine client-only fields on the GraphQL schema rather than prop-drilling or\nReact context. This gives client state the same composability and caching\nguarantees as server data. Use `useClientQuery` for queries that read only\nresolver-defined fields.\n\nSee `<llm-docs>/guides/relay-resolvers/introduction.mdx` for how to define resolvers.\n\n## Critical Anti-Patterns\n\n### Never copy Relay data into React state\n\nThis is the single most important rule. Do not read data from `useFragment` and\ncopy it into `useState`, and do not update that state manually in mutation\n`onCompleted` callbacks.\n\n```tsx\n// WRONG: Copying Relay data into React state\nfunction UserProfile({userKey}) {\n  const data = useFragment(UserProfileFragment, userKey);\n  const [name, setName] = useState(data.name); // broken\n\n  const [commit] = useMutation(UpdateNameMutation);\n  const handleSave = (newName) => {\n    commit({\n      variables: {name: newName},\n      onCompleted: (response) => {\n        setName(response.updateName.user.name); // broken\n      },\n    });\n  };\n  return <span>{name}</span>;\n}\n```\n\nWhy this is wrong: Relay's normalized store is the single source of truth. When\na mutation returns updated data with a matching `id`, Relay automatically\nupdates every component reading that data via `useFragment`. By copying into\n`useState`, you create a second source of truth that Relay cannot update. The\ncomponent will show stale data whenever the record is updated by another\nmutation, subscription, or refetch elsewhere in the app.\n\n```tsx\n// CORRECT: Read directly from the fragment\nfunction UserProfile({userKey}) {\n  const data = useFragment(UserProfileFragment, userKey);\n  const [commit, isInFlight] = useMutation(UpdateNameMutation);\n\n  const handleSave = (newName) => {\n    commit({variables: {name: newName}});\n    // No onCompleted needed — Relay updates the store automatically,\n    // and useFragment re-renders this component with the new data.\n  };\n  return <span>{data.name}</span>;\n}\n```\n\nSimilarly, do not store a fragment key (the `$key` prop) in React state. Relay\ngarbage collects data that is no longer retained by a mounted query component —\nif the component that originally fetched the data unmounts, a stashed key may\npoint to data that is no longer in the store.\n\n### Maintain fragment co-location\n\nDo not fetch all data in a parent's query and pass raw data objects as props to\nchildren. This defeats data masking and creates tight coupling — adding a field\nto a child component requires editing the parent's query. Note that the\n`relay/unused-fields` lint rule will flag fields selected in the parent that\nare only used by children — this is a good signal that you need to extract a\nfragment.\n\n```tsx\n// WRONG: Parent fetches everything, passes raw data\nfunction Parent({queryRef}) {\n  const data = usePreloadedQuery(graphql`\n    query ParentQuery {\n      user {\n        name\n        email\n        avatarUrl\n      }\n    }\n  `, queryRef);\n  return <UserCard name={data.user.name} avatarUrl={data.user.avatarUrl} />;\n}\n\n// CORRECT: Child declares its own fragment\nfunction Parent({queryRef}) {\n  const data = usePreloadedQuery(graphql`\n    query ParentQuery {\n      user {\n        ...UserCard_user\n      }\n    }\n  `, queryRef);\n  return <UserCard user={data.user} />;\n}\n```\n\n### Spread fragments into mutation responses\n\nDo not select fields individually in both a fragment and a mutation response —\nthey will drift out of sync. Spread the fragment instead:\n\n```graphql\n# WRONG\nmutation UpdateUserMutation($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    user { id, name, email, avatarUrl }\n  }\n}\n\n# CORRECT\nmutation UpdateUserMutation($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    user { ...UserCard_user }\n  }\n}\n```\n\n## Correctness\n\n### Use `optimisticUpdater` for store-dependent values\n\nIf an optimistic value depends on current store state (e.g., incrementing a\nlike count), use `optimisticUpdater` instead of `optimisticResponse`. Multiple\noverlapping optimistic responses can compound incorrectly — two simultaneous\n\"like\" mutations both read count=5 and set count=6, instead of 5→6→7. When one\nrolls back, the store is left in an inconsistent state.\n\n### Invalidate data after wide-effect mutations\n\nWhen a mutation has side effects too broad to capture in a single response\npayload, use `invalidateRecord()` for targeted invalidation or\n`invalidateStore()` for global invalidation. Pair with\n`useSubscribeToInvalidationState` on mounted components to trigger refetches\nfor stale data automatically.\n\n### Handle staleness explicitly\n\nRelay treats cached data as fresh **indefinitely** by default. Two approaches:\n\n- **Time-based**: Set `queryCacheExpirationTime` on the Relay Store to\n  automatically mark data stale after a duration.\n- **Event-based**: Call `invalidateRecord()` after mutations whose side effects\n  extend beyond the mutation response payload.\n\nWithout explicit staleness handling, components can display arbitrarily old data\nafter the user returns to a previously visited screen.\n\n### Single artifact directory for type safety\n\nWithout setting `artifactDirectory` in the compiler config, fragment references\nmay default to `any`, losing type safety. Set it and align your bundler's\nmodule resolution accordingly. See `<llm-docs>/getting-started/compiler-config.mdx`.\n\n### Use `@updatable` for store manipulation\n\nPrefer typesafe updatable queries/fragments over raw store manipulation with\nstring-based field access (e.g., `store.get(id).setValue(newName, 'name')`).\nUpdatable fragments provide getters and setters, reducing the risk of typos\nand type mismatches.\n\n### Avoid unnecessary refetches after mutations\n\nDo not call `refetch()` or `fetchQuery()` after mutations when spreading\ncomponent fragments in the mutation response would auto-update the store. Each\nunnecessary refetch is a wasted network request and delays the UI update.\n\nReserve manual refetches for cases where the mutation's side effects are too\nbroad to capture in the response payload — and in those cases, prefer\n`invalidateRecord()` (see above).\n\n### Use subscriptions for real-time data\n\nPrefer GraphQL Subscriptions over polling (`setInterval` + `fetchQuery`) or\nmanual refresh buttons for data that must stay current. Subscriptions push\nupdates only when data changes and integrate with Relay's normalized store\nautomatically.\n\n## Naming Conventions\n\nRelay **enforces** that operation names match the module (file) they are defined\nin. Mismatched names cause compiler errors, not just style warnings.\n\n| Element | Convention | Example |\n|---------|-----------|---------|\n| Fragment | `ComponentName_propName` | `UserCard_user` |\n| Query | `ComponentNameQuery` | `HomePageQuery` |\n| Mutation | `ComponentNameMutation` | `LikeButtonMutation` |\n| Generated files | `__generated__/*.graphql` | Never edit these |\n\nThe module name is the filename stripped of all extensions (`.react.js`, `.tsx`,\netc.). `UserCard.react.js` → module name `UserCard`.\n\n### Renaming operations when extracting to a new file\n\nWhen moving a component to a new file, rename only the operations **defined in\nthat file** to match the new filename. Do NOT rename fragment spreads that\nreference fragments owned by other modules — those names belong to their\ndefining component.\n\nRenaming an operation also changes its generated type name (e.g.,\n`UserCard_user$key` → `ProfileCard_user$key`), so update all downstream imports\nof those generated types.\n\n### Never hand-edit `__generated__/` files\n\nThe next compiler run overwrites any manual edits. If you see type errors about\nmissing generated types, run the compiler first — the types are just out of\ndate, not missing.\n\n### Verify mutation variable keys after auto-formatting\n\nAuto-formatters and linters can rename variables in ways that silently break\nmutation calls. After running lint auto-fix, verify that variable keys in\n`commit({ variables: { ... } })` still match the generated `Mutation$variables`\ntype (check for `data` vs `input` mismatches in particular).\n","packages/eslint-plugin-relay-internal/README.md":"# eslint-plugin-relay-internal\n\nESLint rules intended to run on Relay's own codebase.\n","packages/eslint-plugin-relay-internal/package.json":"{\n  \"name\": \"eslint-plugin-relay-internal\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"description\": \"ESLint rules intended to run on Relay's own codebase\",\n  \"keywords\": [\n    \"eslint\",\n    \"eslintplugin\",\n    \"eslint-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/relay-test-utils-internal\"\n  },\n  \"main\": \"./lib/index.js\",\n  \"exports\": \"./lib/index.js\",\n  \"dependencies\": {},\n  \"engines\": {\n    \"node\": \"^14.17.0 || ^16.0.0 || >= 18.0.0\"\n  },\n  \"peerDependencies\": {\n    \"eslint\": \">=7\"\n  }\n}\n","packages/react-relay/README.md":"## React APIs for Relay\n\nThis package contains a collection of React APIs: Hooks and Components that are\nintegrated with Relay runtime.\n\nExample:\n\n```js\n// @flow\n\nimport type {UserComponent_user$key} from 'UserComponent_user.graphql';\n\nconst React = require('react');\n\nconst {graphql, useFragment} = require('react-relay');\n\ntype Props = {\n  user: UserComponent_user$key,\n};\n\nfunction UserComponent(props: Props) {\n  const data = useFragment(\n    graphql`\n      fragment UserComponent_user on User {\n        name\n        profile_picture(scale: 2) {\n          uri\n        }\n      }\n    `,\n    props.user,\n  );\n\n  return (\n    <>\n      <h1>{data.name}</h1>\n      <div>\n        <img src={data.profile_picture?.uri} />\n      </div>\n    </>\n  );\n}\n```\n\nFor complete API reference, visit https://relay.dev/.\n","packages/react-relay/package.json":"{\n  \"name\": \"react-relay\",\n  \"description\": \"A framework for building GraphQL-driven React applications.\",\n  \"version\": \"21.0.1\",\n  \"keywords\": [\n    \"graphql\",\n    \"relay\",\n    \"react\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/react-relay\"\n  },\n  \"dependencies\": {\n    \"@babel/runtime\": \"^7.25.0\",\n    \"fbjs\": \"^3.0.2\",\n    \"invariant\": \"^2.2.4\",\n    \"nullthrows\": \"^1.1.1\",\n    \"relay-runtime\": \"21.0.1\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.9.0 || ^17 || ^18 || ^19\"\n  },\n  \"directories\": {\n    \"\": \"./\"\n  },\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"haste_commonjs\": true\n}\n","packages/relay-compiler/package.json":"{\n  \"name\": \"relay-compiler\",\n  \"description\": \"A compiler tool for building GraphQL-driven applications.\",\n  \"version\": \"21.0.1\",\n  \"keywords\": [\n    \"graphql\",\n    \"relay\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/relay-compiler\"\n  },\n  \"main\": \"index.js\",\n  \"bin\": \"cli.js\"\n}\n","packages/babel-plugin-relay/README.md":"## babel-plugin-relay\n\nRelay requires a Babel plugin to convert GraphQL tags to runtime artifacts.\n\nA _very_ simplified example of what this plugin is doing:\n\n```js\n// It converts this code\nconst fragment = graphql`\n  fragment User_fragment on User {\n    name\n  }\n`;\n\n// To require generated ASTs for fragments and queries\nconst fragment = require('__generated__/User_fragment.graphql');\n```\n\n## Plugin Configuration\n\n`babel-plugin-relay` will discover the config if:\n\n- There is a `relay.config.json`, `relay.config.js` file at the root of the\n  project (i.e. in the same folder as the `package.json` file).\n- The `package.json` file contains a `\"relay\"` key.\n\n> [!IMPORTANT]\n> This Babel plugin does not support `relay.config.mjs` or `package.json` with `\"type\": \"module\"`.\n\n### Supported configuration options for `babel-plugin-relay`\n\n- `artifactDirectory` A specific directory to output all artifacts to. When\n  enabling this the babel plugin needs `artifactDirectory` to be set as well.\n  [string]\n- `eagerEsModules` This option enables emitting ES modules artifacts.\n  [boolean][default: false]\n- `codegenCommand` The command to run to compile Relay files. [string]\n- `isDevVariableName` Name of the global variable for dev mode (e.g. `__DEV__`).\n  [string]\n- `jsModuleFormat` Formatting style for generated files. `commonjs` or `haste`.\n  Default is `commonjs`. [string]\n\n[Configuration Instructions](https://relay.dev/docs/getting-started/installation-and-setup/#set-up-babel-plugin-relay)\n","packages/relay-compiler/README.md":"# Relay Compiler\n\nSee https://relay.dev/docs/next/guides/compiler/\n","packages/relay-e2e-test/README.md":"# relay-e2e-test Documentation\n\nPath: `packages/relay-e2e-test/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/README.md)","packages/relay-e2e-test/package.json":"# Relay-e2e-test Skill\n\nPath: `packages/relay-e2e-test/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/package.json)","packages/relay-e2e-test/tsconfig.json":"# Relay-e2e-test Skill\n\nPath: `packages/relay-e2e-test/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/tsconfig.json)","packages/relay-e2e-test/tsconfig.template.json":"# Relay-e2e-test Skill\n\nPath: `packages/relay-e2e-test/tsconfig.template.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/tsconfig.template.json)","packages/relay-runtime/README.md":"# relay-runtime Documentation\n\nPath: `packages/relay-runtime/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-runtime/README.md)","packages/relay-runtime/package.json":"# Relay-runtime Skill\n\nPath: `packages/relay-runtime/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-runtime/package.json)","packages/relay-runtime/tsconfig.json":"# Relay-runtime Skill\n\nPath: `packages/relay-runtime/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-runtime/tsconfig.json)","packages/relay-test-utils-internal/README.md":"# relay-test-utils-internal Documentation\n\nPath: `packages/relay-test-utils-internal/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils-internal/README.md)","packages/relay-test-utils-internal/package.json":"# Relay-test-utils-internal Skill\n\nPath: `packages/relay-test-utils-internal/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils-internal/package.json)","packages/relay-test-utils/README.md":"# relay-test-utils Documentation\n\nPath: `packages/relay-test-utils/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils/README.md)","packages/relay-test-utils/package.json":"# Relay-test-utils Skill\n\nPath: `packages/relay-test-utils/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils/package.json)","packages/relay-e2e-test/fixtures/data-driven-dependencies/module.md":"# Data-driven-dependencies Skill\n\nPath: `packages/relay-e2e-test/fixtures/data-driven-dependencies/module.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/data-driven-dependencies/module.md)","packages/relay-e2e-test/fixtures/data-driven-dependencies/module.snap.md":"# Data-driven-dependencies Skill\n\nPath: `packages/relay-e2e-test/fixtures/data-driven-dependencies/module.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/data-driven-dependencies/module.snap.md)","packages/relay-e2e-test/fixtures/mixed-interface/nested-field.md":"# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/nested-field.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/nested-field.md)","packages/relay-e2e-test/fixtures/mixed-interface/nested-field.snap.md":"# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/nested-field.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/nested-field.snap.md)","packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.md":"# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.md)","packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.snap.md":"# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.snap.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction.md)","packages/relay-e2e-test/fixtures/mutations/useMutationAction.snap.md":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction.snap.md)","packages/relay-e2e-test/fixtures/queries/greeting.md":"# Queries Skill\n\nPath: `packages/relay-e2e-test/fixtures/queries/greeting.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/queries/greeting.md)","packages/relay-e2e-test/fixtures/queries/greeting.snap.md":"# Queries Skill\n\nPath: `packages/relay-e2e-test/fixtures/queries/greeting.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/queries/greeting.snap.md)","packages/relay-e2e-test/fixtures/typechecking/unselected-field.md":"# Typechecking Skill\n\nPath: `packages/relay-e2e-test/fixtures/typechecking/unselected-field.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/typechecking/unselected-field.md)","packages/relay-e2e-test/fixtures/typechecking/unselected-field.snap.md":"# Typechecking Skill\n\nPath: `packages/relay-e2e-test/fixtures/typechecking/unselected-field.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/typechecking/unselected-field.snap.md)","packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-github.md":"# References Skill\n\nPath: `packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-github.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-github.md)","packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-internal.md":"# References Skill\n\nPath: `packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-internal.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-internal.md)","packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/writing-fixtures.md":"# References Skill\n\nPath: `packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/writing-fixtures.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/writing-fixtures.md)"},"items":[{"name":"package.json","path":"packages/babel-plugin-relay/package.json","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/babel-plugin-relay/package.json","title":"babel-plugin-relay","category":"anthropic-skill","format":"json","content":"{\n  \"name\": \"babel-plugin-relay\",\n  \"description\": \"A Babel Plugin for use with Relay applications.\",\n  \"version\": \"21.0.1\",\n  \"keywords\": [\n    \"graphql\",\n    \"relay\",\n    \"babel\",\n    \"babel-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/babel-plugin-relay\"\n  },\n  \"dependencies\": {\n    \"babel-plugin-macros\": \"^2.0.0\",\n    \"cosmiconfig\": \"^5.0.5\",\n    \"graphql\": \"17.0.2\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.25.2\",\n    \"prettier\": \"3.9.4\"\n  },\n  \"resolutions\": {\n    \"@babel/traverse\": \"^7.23.2\"\n  }\n}\n","frontmatter":{"name":"babel-plugin-relay","description":"A Babel Plugin for use with Relay applications.","version":"21.0.1","keywords":["graphql","relay","babel","babel-plugin"],"license":"MIT","homepage":"https://relay.dev","bugs":"https://github.com/facebook/relay/issues","repository":{"type":"git","url":"https://github.com/facebook/relay.git","directory":"packages/babel-plugin-relay"},"dependencies":{"babel-plugin-macros":"^2.0.0","cosmiconfig":"^5.0.5","graphql":"17.0.2"},"devDependencies":{"@babel/core":"^7.25.2","prettier":"3.9.4"},"resolutions":{"@babel/traverse":"^7.23.2"}},"isInternal":false,"tokens":234,"sizeBytes":711},{"name":"package.json","path":"packages/eslint-plugin-relay-internal/package.json","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/eslint-plugin-relay-internal/package.json","title":"eslint-plugin-relay-internal","category":"anthropic-skill","format":"json","content":"{\n  \"name\": \"eslint-plugin-relay-internal\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"description\": \"ESLint rules intended to run on Relay's own codebase\",\n  \"keywords\": [\n    \"eslint\",\n    \"eslintplugin\",\n    \"eslint-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/relay-test-utils-internal\"\n  },\n  \"main\": \"./lib/index.js\",\n  \"exports\": \"./lib/index.js\",\n  \"dependencies\": {},\n  \"engines\": {\n    \"node\": \"^14.17.0 || ^16.0.0 || >= 18.0.0\"\n  },\n  \"peerDependencies\": {\n    \"eslint\": \">=7\"\n  }\n}\n","frontmatter":{"name":"eslint-plugin-relay-internal","private":true,"version":"0.0.0","description":"ESLint rules intended to run on Relay's own codebase","keywords":["eslint","eslintplugin","eslint-plugin"],"license":"MIT","homepage":"https://relay.dev","bugs":"https://github.com/facebook/relay/issues","repository":{"type":"git","url":"https://github.com/facebook/relay.git","directory":"packages/relay-test-utils-internal"},"main":"./lib/index.js","exports":"./lib/index.js","dependencies":{},"engines":{"node":"^14.17.0 || ^16.0.0 || >= 18.0.0"},"peerDependencies":{"eslint":">=7"}},"isInternal":false,"tokens":215,"sizeBytes":688},{"name":"package.json","path":"packages/react-relay/package.json","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/react-relay/package.json","title":"react-relay","category":"anthropic-skill","format":"json","content":"{\n  \"name\": \"react-relay\",\n  \"description\": \"A framework for building GraphQL-driven React applications.\",\n  \"version\": \"21.0.1\",\n  \"keywords\": [\n    \"graphql\",\n    \"relay\",\n    \"react\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/react-relay\"\n  },\n  \"dependencies\": {\n    \"@babel/runtime\": \"^7.25.0\",\n    \"fbjs\": \"^3.0.2\",\n    \"invariant\": \"^2.2.4\",\n    \"nullthrows\": \"^1.1.1\",\n    \"relay-runtime\": \"21.0.1\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.9.0 || ^17 || ^18 || ^19\"\n  },\n  \"directories\": {\n    \"\": \"./\"\n  },\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"haste_commonjs\": true\n}\n","frontmatter":{"name":"react-relay","description":"A framework for building GraphQL-driven React applications.","version":"21.0.1","keywords":["graphql","relay","react"],"license":"MIT","homepage":"https://relay.dev","bugs":"https://github.com/facebook/relay/issues","repository":{"type":"git","url":"https://github.com/facebook/relay.git","directory":"packages/react-relay"},"dependencies":{"@babel/runtime":"^7.25.0","fbjs":"^3.0.2","invariant":"^2.2.4","nullthrows":"^1.1.1","relay-runtime":"21.0.1"},"peerDependencies":{"react":"^16.9.0 || ^17 || ^18 || ^19"},"directories":{"":"./"},"main":"index.js","types":"index.d.ts","haste_commonjs":true},"isInternal":false,"tokens":257,"sizeBytes":783},{"name":"package.json","path":"packages/relay-compiler/package.json","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-compiler/package.json","title":"relay-compiler","category":"anthropic-skill","format":"json","content":"{\n  \"name\": \"relay-compiler\",\n  \"description\": \"A compiler tool for building GraphQL-driven applications.\",\n  \"version\": \"21.0.1\",\n  \"keywords\": [\n    \"graphql\",\n    \"relay\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/relay-compiler\"\n  },\n  \"main\": \"index.js\",\n  \"bin\": \"cli.js\"\n}\n","frontmatter":{"name":"relay-compiler","description":"A compiler tool for building GraphQL-driven applications.","version":"21.0.1","keywords":["graphql","relay"],"license":"MIT","homepage":"https://relay.dev","bugs":"https://github.com/facebook/relay/issues","repository":{"type":"git","url":"https://github.com/facebook/relay.git","directory":"packages/relay-compiler"},"main":"index.js","bin":"cli.js"},"isInternal":false,"tokens":137,"sizeBytes":467},{"name":"running-tests-github.md","path":"packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-github.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-github.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# References Skill\n\nPath: `packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-github.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-github.md)","tokens":300,"sizeBytes":286},{"name":"running-tests-internal.md","path":"packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-internal.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-internal.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# References Skill\n\nPath: `packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-internal.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-internal.md)","tokens":300,"sizeBytes":290},{"name":"writing-fixtures.md","path":"packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/writing-fixtures.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/writing-fixtures.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# References Skill\n\nPath: `packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/writing-fixtures.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/writing-fixtures.md)","tokens":300,"sizeBytes":278},{"name":"SKILL.md","path":"packages/relay-e2e-test/.llms/skills/relay-e2e-test/SKILL.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/SKILL.md","title":"relay-e2e-test","category":"anthropic-skill","format":"markdown","content":"---\nname: relay-e2e-test\ndescription: Write and run markdown-driven e2e tests for Relay. Covers fixture format, server/client code patterns, interaction DSL, snapshots, and running tests.\nallowed-tools: Bash, Read, Edit, Write, AskUserQuestion, mcp__plugin_meta_mux__search_files\nmetadata:\n  oncalls: ['relay']\n  strict: true\n---\n\n# Relay E2E Tests\n\nMarkdown-driven end-to-end tests for Relay. Each test is a self-contained `.md` file that defines a GraphQL server (via [Grats](https://grats.capt.dev/)), a Relay-powered React component, and optional interaction steps. The test harness extracts the code blocks, compiles them with Grats + relay-compiler, renders with React Testing Library, runs interactions, and snapshot-tests the output.\n\nTests run against **Relay runtime packages from source**, so changes are reflected immediately without a build step.\n\n## References\n\nRead the appropriate reference file based on your task:\n\n- **[Writing fixtures](references/writing-fixtures.md)** — fixture format, example, server/client code patterns, interaction DSL, snapshots. Read when creating or modifying test fixtures.\n- **[Running tests (internal)](references/running-tests-internal.md)** — setup, commands, and compiler resolution for fbsource / OD. Read when running tests internally.\n- **[Running tests (GitHub)](references/running-tests-github.md)** — setup, commands, and compiler resolution for the OSS repo. Read when running tests on GitHub.\n","frontmatter":{"name":"relay-e2e-test","description":"Write and run markdown-driven e2e tests for Relay. Covers fixture format, server/client code patterns, interaction DSL, snapshots, and running tests.","allowed-tools":"Bash, Read, Edit, Write, AskUserQuestion, mcp__plugin_meta_mux__search_files","metadata":{"oncalls":["relay"],"strict":true},"allowedTools":["Bash,","Read,","Edit,","Write,","AskUserQuestion,","mcp__plugin_meta_mux__search_files"]},"allowedTools":["Bash,","Read,","Edit,","Write,","AskUserQuestion,","mcp__plugin_meta_mux__search_files"],"isInternal":false,"tokens":318,"sizeBytes":1459},{"name":"module.md","path":"packages/relay-e2e-test/fixtures/data-driven-dependencies/module.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/data-driven-dependencies/module.md","title":"Data-driven-dependencies Skill","category":"anthropic-skill","format":"markdown","content":"# Data-driven-dependencies Skill\n\nPath: `packages/relay-e2e-test/fixtures/data-driven-dependencies/module.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/data-driven-dependencies/module.md)","tokens":300,"sizeBytes":262},{"name":"module.snap.md","path":"packages/relay-e2e-test/fixtures/data-driven-dependencies/module.snap.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/data-driven-dependencies/module.snap.md","title":"Data-driven-dependencies Skill","category":"anthropic-skill","format":"markdown","content":"# Data-driven-dependencies Skill\n\nPath: `packages/relay-e2e-test/fixtures/data-driven-dependencies/module.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/data-driven-dependencies/module.snap.md)","tokens":300,"sizeBytes":272},{"name":"nested-field.md","path":"packages/relay-e2e-test/fixtures/mixed-interface/nested-field.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/nested-field.md","title":"Mixed-interface Skill","category":"anthropic-skill","format":"markdown","content":"# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/nested-field.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/nested-field.md)","tokens":300,"sizeBytes":247},{"name":"nested-field.snap.md","path":"packages/relay-e2e-test/fixtures/mixed-interface/nested-field.snap.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/nested-field.snap.md","title":"Mixed-interface Skill","category":"anthropic-skill","format":"markdown","content":"# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/nested-field.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/nested-field.snap.md)","tokens":300,"sizeBytes":257},{"name":"server-and-resolver-type-share-interface.md","path":"packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.md","title":"Mixed-interface Skill","category":"anthropic-skill","format":"markdown","content":"# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.md)","tokens":300,"sizeBytes":303},{"name":"server-and-resolver-type-share-interface.snap.md","path":"packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.snap.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.snap.md","title":"Mixed-interface Skill","category":"anthropic-skill","format":"markdown","content":"# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.snap.md)","tokens":300,"sizeBytes":313},{"name":"useMutationAction-catch-field-error.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.md)","tokens":300,"sizeBytes":275},{"name":"useMutationAction-catch-field-error.snap.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.snap.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.snap.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.snap.md)","tokens":300,"sizeBytes":285},{"name":"useMutationAction-field-errors.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.md)","tokens":300,"sizeBytes":265},{"name":"useMutationAction-field-errors.snap.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.snap.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.snap.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.snap.md)","tokens":300,"sizeBytes":275},{"name":"useMutationAction-form-action.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.md)","tokens":300,"sizeBytes":263},{"name":"useMutationAction-form-action.snap.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.snap.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.snap.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.snap.md)","tokens":300,"sizeBytes":273},{"name":"useMutationAction-network-error-boundary.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.md)","tokens":300,"sizeBytes":285},{"name":"useMutationAction-network-error-boundary.snap.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.snap.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.snap.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.snap.md)","tokens":300,"sizeBytes":295},{"name":"useMutationAction-network-error-catch.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.md)","tokens":300,"sizeBytes":279},{"name":"useMutationAction-network-error-catch.snap.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.snap.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.snap.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.snap.md)","tokens":300,"sizeBytes":289},{"name":"useMutationAction-optimistic.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.md)","tokens":300,"sizeBytes":261},{"name":"useMutationAction-optimistic.snap.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.snap.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.snap.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.snap.md)","tokens":300,"sizeBytes":271},{"name":"useMutationAction-sequential.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.md)","tokens":300,"sizeBytes":261},{"name":"useMutationAction-sequential.snap.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.snap.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.snap.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.snap.md)","tokens":300,"sizeBytes":271},{"name":"useMutationAction-top-level-field-error.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.md)","tokens":300,"sizeBytes":283},{"name":"useMutationAction-top-level-field-error.snap.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.snap.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.snap.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.snap.md)","tokens":300,"sizeBytes":293},{"name":"useMutationAction.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction.md)","tokens":300,"sizeBytes":239},{"name":"useMutationAction.snap.md","path":"packages/relay-e2e-test/fixtures/mutations/useMutationAction.snap.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction.snap.md","title":"Mutations Skill","category":"anthropic-skill","format":"markdown","content":"# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction.snap.md)","tokens":300,"sizeBytes":249},{"name":"greeting.md","path":"packages/relay-e2e-test/fixtures/queries/greeting.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/queries/greeting.md","title":"Queries Skill","category":"anthropic-skill","format":"markdown","content":"# Queries Skill\n\nPath: `packages/relay-e2e-test/fixtures/queries/greeting.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/queries/greeting.md)","tokens":300,"sizeBytes":215},{"name":"greeting.snap.md","path":"packages/relay-e2e-test/fixtures/queries/greeting.snap.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/queries/greeting.snap.md","title":"Queries Skill","category":"anthropic-skill","format":"markdown","content":"# Queries Skill\n\nPath: `packages/relay-e2e-test/fixtures/queries/greeting.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/queries/greeting.snap.md)","tokens":300,"sizeBytes":225},{"name":"unselected-field.md","path":"packages/relay-e2e-test/fixtures/typechecking/unselected-field.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/typechecking/unselected-field.md","title":"Typechecking Skill","category":"anthropic-skill","format":"markdown","content":"# Typechecking Skill\n\nPath: `packages/relay-e2e-test/fixtures/typechecking/unselected-field.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/typechecking/unselected-field.md)","tokens":300,"sizeBytes":246},{"name":"unselected-field.snap.md","path":"packages/relay-e2e-test/fixtures/typechecking/unselected-field.snap.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/typechecking/unselected-field.snap.md","title":"Typechecking Skill","category":"anthropic-skill","format":"markdown","content":"# Typechecking Skill\n\nPath: `packages/relay-e2e-test/fixtures/typechecking/unselected-field.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/typechecking/unselected-field.snap.md)","tokens":300,"sizeBytes":256},{"name":"package.json","path":"packages/relay-e2e-test/package.json","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/package.json","title":"Relay-e2e-test Skill","category":"anthropic-skill","format":"json","content":"# Relay-e2e-test Skill\n\nPath: `packages/relay-e2e-test/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/package.json)","tokens":300,"sizeBytes":190},{"name":"tsconfig.json","path":"packages/relay-e2e-test/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/tsconfig.json","title":"Relay-e2e-test Skill","category":"anthropic-skill","format":"json","content":"# Relay-e2e-test Skill\n\nPath: `packages/relay-e2e-test/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/tsconfig.json)","tokens":300,"sizeBytes":192},{"name":"tsconfig.template.json","path":"packages/relay-e2e-test/tsconfig.template.json","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/tsconfig.template.json","title":"Relay-e2e-test Skill","category":"anthropic-skill","format":"json","content":"# Relay-e2e-test Skill\n\nPath: `packages/relay-e2e-test/tsconfig.template.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/tsconfig.template.json)","tokens":300,"sizeBytes":210},{"name":"package.json","path":"packages/relay-runtime/package.json","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-runtime/package.json","title":"Relay-runtime Skill","category":"anthropic-skill","format":"json","content":"# Relay-runtime Skill\n\nPath: `packages/relay-runtime/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-runtime/package.json)","tokens":300,"sizeBytes":187},{"name":"tsconfig.json","path":"packages/relay-runtime/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-runtime/tsconfig.json","title":"Relay-runtime Skill","category":"anthropic-skill","format":"json","content":"# Relay-runtime Skill\n\nPath: `packages/relay-runtime/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-runtime/tsconfig.json)","tokens":300,"sizeBytes":189},{"name":"package.json","path":"packages/relay-test-utils-internal/package.json","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils-internal/package.json","title":"Relay-test-utils-internal Skill","category":"anthropic-skill","format":"json","content":"# Relay-test-utils-internal Skill\n\nPath: `packages/relay-test-utils-internal/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils-internal/package.json)","tokens":300,"sizeBytes":223},{"name":"package.json","path":"packages/relay-test-utils/package.json","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils/package.json","title":"Relay-test-utils Skill","category":"anthropic-skill","format":"json","content":"# Relay-test-utils Skill\n\nPath: `packages/relay-test-utils/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils/package.json)","tokens":300,"sizeBytes":196},{"name":"SKILL.md","path":"skills/relay-best-practices/SKILL.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/skills/relay-best-practices/SKILL.md","title":"relay-best-practices","category":"anthropic-skill","format":"markdown","content":"---\nname: relay-best-practices\ndescription: >-\n  Best practices for writing idiomatic Relay code. ALWAYS use this skill when\n  writing or modifying React components that use Relay for data fetching. Covers\n  fragments, queries, mutations, pagination, and common anti-patterns. Use when\n  you see `useFragment`, `useLazyLoadQuery`, `usePreloadedQuery`, `useMutation`,\n  `usePaginationFragment`, `graphql` template literals, `react-relay` imports,\n  or `__generated__/*.graphql` files. Also use when asked to explain Relay\n  concepts, debug Relay issues, or review Relay code.\n---\n\n# Relay Best Practices\n\nRelay is a GraphQL client for React that enforces colocated, composable, and\ntype-safe data fetching. Its core insight is that each component should declare\nexactly what data it needs via GraphQL fragments, and Relay handles the rest —\nfetching, caching, consistency, and updates.\n\nThis skill provides opinionated guidance on which patterns to prefer. For\ndetailed API documentation, read the relevant page from the doc map below.\n\n## Documentation\n\nRelay ships LLM-friendly docs in `node_modules/relay-runtime/llm-docs/`\n(available after v20.1.1). For older versions, fetch the same files from\n`https://raw.githubusercontent.com/facebook/relay/main/website/docs/`.\n\nPaths below are relative to this directory (`<llm-docs>/`). Read the relevant\npage before writing Relay code. Key docs:\n\n| Topic | Path |\n|-------|------|\n| Core concepts & philosophy | `principles-and-architecture/thinking-in-relay.mdx` |\n| Fragments | `guided-tour/rendering/fragments.mdx` |\n| Queries | `guided-tour/rendering/queries.mdx` |\n| Mutations | `guided-tour/updating-data/graphql-mutations.mdx` |\n| Pagination | `guided-tour/list-data/pagination.mdx` |\n| Refetching | `guided-tour/refetching/refetching-queries-with-different-data.mdx` |\n| `useFragment` | `api-reference/hooks/use-fragment.mdx` |\n| `usePreloadedQuery` | `api-reference/hooks/use-preloaded-query.mdx` |\n| `useQueryLoader` / `loadQuery` | `api-reference/hooks/load-query.mdx` |\n| `useMutation` | `api-reference/hooks/use-mutation.mdx` |\n| `usePaginationFragment` | `api-reference/hooks/use-pagination-fragment.mdx` |\n| `@throwOnFieldError` | `guides/throw-on-field-error-directive.mdx` |\n| `@catch` directive | `guides/catch-directive.mdx` |\n| Semantic nullability | `guides/semantic-nullability.mdx` |\n| Relay Resolvers | `guides/relay-resolvers/introduction.mdx` |\n| Testing | `guides/testing-relay-components.mdx` |\n| Compiler setup | `getting-started/compiler.mdx` |\n| Compiler configuration | `getting-started/compiler-config.mdx` |\n| Lint rules (ESLint plugin) | `getting-started/lint-rules.mdx` |\n\n**For performance-specific guidance** (query placement, `@defer`, pagination,\nfetch policies, caching, fragment granularity), see the companion\n`relay-performance` skill.\n\n## Core Philosophy\n\nThese principles are the foundation of every decision below. When in doubt,\nrefer back to them.\n\n- **Co-location**: Each component declares its own data requirements via a\n  GraphQL fragment, right next to the rendering code. Data needs travel with the\n  component, not separately.\n- **Data masking**: A component can only access the fields it explicitly\n  selected in its own fragment. Parents cannot see child fragment data, and vice\n  versa. This prevents implicit coupling between components.\n- **Composition**: Fragments compose into parent fragments and ultimately into\n  queries, forming a tree that mirrors the component tree. The compiler flattens\n  this into a single network request per query.\n- **Render-as-you-fetch**: Start fetching data before the component that needs\n  it renders. This avoids sequential request waterfalls.\n- **Normalized store**: Relay maintains a flat, ID-keyed cache. When a mutation\n  returns updated data, every component reading that data re-renders\n  automatically. You do not need to manually propagate changes.\n\n## Compiler Workflow\n\nRelay uses an ahead-of-time compiler that reads `graphql` tagged template\nliterals in your code and generates runtime artifacts and TypeScript/Flow types.\n\n### Finding the config\n\nThe compiler looks for its config in these locations (checked in order):\n- `relay.config.{json,js,mjs,ts}` in the project root\n- A `\"relay\"` key in `package.json`\n\nSee `<llm-docs>/getting-started/compiler-config.mdx` for the full config schema.\nYou can also emit a JSON Schema for the config by running\n`npx relay-compiler config-json-schema`.\n\n### Running the compiler\n\nRun `npx relay-compiler` after any change to the contents of a `graphql` tagged\ntemplate literal or the docblock of a Relay Resolver. Some projects add this as\na script in `package.json` (e.g., `yarn relay`). The compiler also supports watch mode (`--watch`), but avoid using it in\nnon-interactive contexts since the process never exits.\n\nGenerated files go into `__generated__/` directories next to the source files.\nNever edit these files — they are overwritten on every compiler run. If you see\ntype errors about missing generated types, run the compiler first — the\ntypes are likely just out of date.\n\n## Lint Rules\n\nRelay's ESLint plugin (`eslint-plugin-relay`) is a key part of the developer\nexperience. Two rules are especially important:\n\n- `relay/unused-fields` — detects GraphQL fields that are selected in a\n  fragment but never read in the component. This prevents the \"append-only\n  query\" problem where fragments accumulate unused fields over time, fetching\n  data no component actually needs.\n- `relay/no-future-added-value` — prevents explicitly handling the\n  `\"%future added value\"` enum placeholder that Relay inserts to ensure you\n  handle the possibility of new enum variants being added by the server.\n\nSee `<llm-docs>/getting-started/lint-rules.mdx` for installation and configuration.\n\n## Decision Rules\n\n### Queries belong at roots — never in hooks\n\nQueries belong at **route entrypoints** (the top-level component for a URL).\nHooks are leaves — reused across many components. A query inside a hook fires\nlate (after the hook's host renders) AND duplicates across every caller. The fix\nis always: accept a fragment key as a parameter, use `useFragment`.\n\nUse `usePreloadedQuery` + `useQueryLoader` (or `loadQuery`). Start the fetch in\nan event handler, route transition, or during app initialization — before the\ncomponent renders. `useLazyLoadQuery` does not start fetching until render,\ncreating waterfalls. See `<llm-docs>/guided-tour/rendering/queries.mdx` for the full pattern.\n\n### Before fixing where a query lives, ask if it should exist\n\n| Question | If YES |\n|----------|--------|\n| Parent already fetches this GraphQL type? | Delete query, use `useFragment` |\n| Component only fetches and passes data down? | Delete the wrapper component entirely (loader anti-pattern) |\n| Query is inside a custom hook? | Delete query, accept a fragment key param |\n| Two components fetch the same data? | Delete one query, fetch in a common ancestor |\n| Data is only used for logging/analytics? | Move to `@defer` or server-side logging |\n| Data is static config (same for every user)? | Inject server-side, no round-trip needed |\n\n### `loadQuery` in `useEffect` is worse than `useLazyLoadQuery`\n\n`useEffect` runs **after paint**, so the fetch starts even later than\n`useLazyLoadQuery` (which at least starts during render). Call `loadQuery` in\nevent handlers, route transitions, or app initialization — never in effects.\n\n### Walking the ancestor tree for `useFragment`\n\nWhen deciding whether `useFragment` can replace a query, walk **up** the\ncomponent tree from your component. Stop at: route boundaries, feature gates,\nconditional renders, or user-triggered interactions. Keep walking through:\nunconditional renders, layout/wrapper components, context providers.\n\nIf any ancestor already queries the GraphQL type you need, `useFragment` is\nthe answer. Threading fragment keys through several layers of props is fine —\nit IS the correct pattern.\n\n### Don't default query variables to empty values\n\nNever default a query variable to `''`, `0`, or `null` when the real value is\nunavailable. This fires the query with bad data, returning wrong results or\nerrors. Instead, use conditional rendering (`if (!id) return null`) or\n`@include`/`@skip` directives to omit the field entirely.\n\n### Data flow: Always use fragments\n\nEvery component that displays server data should declare a fragment and receive\na fragment reference (the `$key` type) as a prop. The parent spreads the\nchild's fragment in its own query or fragment and passes the result down. See\nthe \"Maintain fragment co-location\" anti-pattern below for an example.\n\n### Mutations: Spread fragments into responses\n\nSpread the consuming component's fragment into the mutation response rather than\nselecting fields individually. This keeps them in sync automatically. See the\nanti-pattern example below.\n\n### Error handling: Use `@throwOnFieldError` and `@catch`\n\nThe recommended approach for handling field errors and nullability is to add\n`@throwOnFieldError` to your fragment or query. This causes Relay to throw a\nJavaScript exception if a field error is encountered, which can be caught by a\nReact error boundary. It also enables non-null types for `@semanticNonNull`\nfields, eliminating unnecessary null checks. Note that this pattern depends on\nReact error boundaries being configured in your application — proceed with\ncaution if error boundaries are not set up robustly.\n\nFor fields where you want to handle errors locally instead of throwing, use\n`@catch` to receive errors inline as `{ ok: true, value: T } | { ok: false,\nerrors: [...] }`.\n\n`@required` is also available for declaring that specific fields must be\nnon-null, but `@throwOnFieldError` + `@catch` is the preferred pattern for new\ncode.\n\nSee `<llm-docs>/guides/throw-on-field-error-directive.mdx`, `<llm-docs>/guides/catch-directive.mdx`,\nand `<llm-docs>/guides/semantic-nullability.mdx`.\n\n### Pagination: Use the three-directive pattern\n\nAlways use `@argumentDefinitions` (for cursor/count variables),\n`@refetchable` (to auto-generate the pagination query), and `@connection` (to\nidentify the connection for store management) together. Never write manual\npagination queries. See `<llm-docs>/guided-tour/list-data/pagination.mdx`.\n\n### Client state: Prefer Relay Resolvers\n\nWhen multiple components need to read client-side data, use Relay Resolvers to\ndefine client-only fields on the GraphQL schema rather than prop-drilling or\nReact context. This gives client state the same composability and caching\nguarantees as server data. Use `useClientQuery` for queries that read only\nresolver-defined fields.\n\nSee `<llm-docs>/guides/relay-resolvers/introduction.mdx` for how to define resolvers.\n\n## Critical Anti-Patterns\n\n### Never copy Relay data into React state\n\nThis is the single most important rule. Do not read data from `useFragment` and\ncopy it into `useState`, and do not update that state manually in mutation\n`onCompleted` callbacks.\n\n```tsx\n// WRONG: Copying Relay data into React state\nfunction UserProfile({userKey}) {\n  const data = useFragment(UserProfileFragment, userKey);\n  const [name, setName] = useState(data.name); // broken\n\n  const [commit] = useMutation(UpdateNameMutation);\n  const handleSave = (newName) => {\n    commit({\n      variables: {name: newName},\n      onCompleted: (response) => {\n        setName(response.updateName.user.name); // broken\n      },\n    });\n  };\n  return <span>{name}</span>;\n}\n```\n\nWhy this is wrong: Relay's normalized store is the single source of truth. When\na mutation returns updated data with a matching `id`, Relay automatically\nupdates every component reading that data via `useFragment`. By copying into\n`useState`, you create a second source of truth that Relay cannot update. The\ncomponent will show stale data whenever the record is updated by another\nmutation, subscription, or refetch elsewhere in the app.\n\n```tsx\n// CORRECT: Read directly from the fragment\nfunction UserProfile({userKey}) {\n  const data = useFragment(UserProfileFragment, userKey);\n  const [commit, isInFlight] = useMutation(UpdateNameMutation);\n\n  const handleSave = (newName) => {\n    commit({variables: {name: newName}});\n    // No onCompleted needed — Relay updates the store automatically,\n    // and useFragment re-renders this component with the new data.\n  };\n  return <span>{data.name}</span>;\n}\n```\n\nSimilarly, do not store a fragment key (the `$key` prop) in React state. Relay\ngarbage collects data that is no longer retained by a mounted query component —\nif the component that originally fetched the data unmounts, a stashed key may\npoint to data that is no longer in the store.\n\n### Maintain fragment co-location\n\nDo not fetch all data in a parent's query and pass raw data objects as props to\nchildren. This defeats data masking and creates tight coupling — adding a field\nto a child component requires editing the parent's query. Note that the\n`relay/unused-fields` lint rule will flag fields selected in the parent that\nare only used by children — this is a good signal that you need to extract a\nfragment.\n\n```tsx\n// WRONG: Parent fetches everything, passes raw data\nfunction Parent({queryRef}) {\n  const data = usePreloadedQuery(graphql`\n    query ParentQuery {\n      user {\n        name\n        email\n        avatarUrl\n      }\n    }\n  `, queryRef);\n  return <UserCard name={data.user.name} avatarUrl={data.user.avatarUrl} />;\n}\n\n// CORRECT: Child declares its own fragment\nfunction Parent({queryRef}) {\n  const data = usePreloadedQuery(graphql`\n    query ParentQuery {\n      user {\n        ...UserCard_user\n      }\n    }\n  `, queryRef);\n  return <UserCard user={data.user} />;\n}\n```\n\n### Spread fragments into mutation responses\n\nDo not select fields individually in both a fragment and a mutation response —\nthey will drift out of sync. Spread the fragment instead:\n\n```graphql\n# WRONG\nmutation UpdateUserMutation($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    user { id, name, email, avatarUrl }\n  }\n}\n\n# CORRECT\nmutation UpdateUserMutation($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    user { ...UserCard_user }\n  }\n}\n```\n\n## Correctness\n\n### Use `optimisticUpdater` for store-dependent values\n\nIf an optimistic value depends on current store state (e.g., incrementing a\nlike count), use `optimisticUpdater` instead of `optimisticResponse`. Multiple\noverlapping optimistic responses can compound incorrectly — two simultaneous\n\"like\" mutations both read count=5 and set count=6, instead of 5→6→7. When one\nrolls back, the store is left in an inconsistent state.\n\n### Invalidate data after wide-effect mutations\n\nWhen a mutation has side effects too broad to capture in a single response\npayload, use `invalidateRecord()` for targeted invalidation or\n`invalidateStore()` for global invalidation. Pair with\n`useSubscribeToInvalidationState` on mounted components to trigger refetches\nfor stale data automatically.\n\n### Handle staleness explicitly\n\nRelay treats cached data as fresh **indefinitely** by default. Two approaches:\n\n- **Time-based**: Set `queryCacheExpirationTime` on the Relay Store to\n  automatically mark data stale after a duration.\n- **Event-based**: Call `invalidateRecord()` after mutations whose side effects\n  extend beyond the mutation response payload.\n\nWithout explicit staleness handling, components can display arbitrarily old data\nafter the user returns to a previously visited screen.\n\n### Single artifact directory for type safety\n\nWithout setting `artifactDirectory` in the compiler config, fragment references\nmay default to `any`, losing type safety. Set it and align your bundler's\nmodule resolution accordingly. See `<llm-docs>/getting-started/compiler-config.mdx`.\n\n### Use `@updatable` for store manipulation\n\nPrefer typesafe updatable queries/fragments over raw store manipulation with\nstring-based field access (e.g., `store.get(id).setValue(newName, 'name')`).\nUpdatable fragments provide getters and setters, reducing the risk of typos\nand type mismatches.\n\n### Avoid unnecessary refetches after mutations\n\nDo not call `refetch()` or `fetchQuery()` after mutations when spreading\ncomponent fragments in the mutation response would auto-update the store. Each\nunnecessary refetch is a wasted network request and delays the UI update.\n\nReserve manual refetches for cases where the mutation's side effects are too\nbroad to capture in the response payload — and in those cases, prefer\n`invalidateRecord()` (see above).\n\n### Use subscriptions for real-time data\n\nPrefer GraphQL Subscriptions over polling (`setInterval` + `fetchQuery`) or\nmanual refresh buttons for data that must stay current. Subscriptions push\nupdates only when data changes and integrate with Relay's normalized store\nautomatically.\n\n## Naming Conventions\n\nRelay **enforces** that operation names match the module (file) they are defined\nin. Mismatched names cause compiler errors, not just style warnings.\n\n| Element | Convention | Example |\n|---------|-----------|---------|\n| Fragment | `ComponentName_propName` | `UserCard_user` |\n| Query | `ComponentNameQuery` | `HomePageQuery` |\n| Mutation | `ComponentNameMutation` | `LikeButtonMutation` |\n| Generated files | `__generated__/*.graphql` | Never edit these |\n\nThe module name is the filename stripped of all extensions (`.react.js`, `.tsx`,\netc.). `UserCard.react.js` → module name `UserCard`.\n\n### Renaming operations when extracting to a new file\n\nWhen moving a component to a new file, rename only the operations **defined in\nthat file** to match the new filename. Do NOT rename fragment spreads that\nreference fragments owned by other modules — those names belong to their\ndefining component.\n\nRenaming an operation also changes its generated type name (e.g.,\n`UserCard_user$key` → `ProfileCard_user$key`), so update all downstream imports\nof those generated types.\n\n### Never hand-edit `__generated__/` files\n\nThe next compiler run overwrites any manual edits. If you see type errors about\nmissing generated types, run the compiler first — the types are just out of\ndate, not missing.\n\n### Verify mutation variable keys after auto-formatting\n\nAuto-formatters and linters can rename variables in ways that silently break\nmutation calls. After running lint auto-fix, verify that variable keys in\n`commit({ variables: { ... } })` still match the generated `Mutation$variables`\ntype (check for `data` vs `input` mismatches in particular).\n","frontmatter":{"name":"relay-best-practices","description":"Best practices for writing idiomatic Relay code. ALWAYS use this skill when writing or modifying React components that use Relay for data fetching. Covers fragments, queries, mutations, pagination, and common anti-patterns. Use when you see `useFragment`, `useLazyLoadQuery`, `usePreloadedQuery`, `useMutation`, `usePaginationFragment`, `graphql` template literals, `react-relay` imports, or `__generated__/*.graphql` files. Also use when asked to explain Relay concepts, debug Relay issues, or review Relay code."},"isInternal":false,"tokens":4183,"sizeBytes":18462},{"name":"SKILL.md","path":"skills/relay-performance/SKILL.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/skills/relay-performance/SKILL.md","title":"relay-performance","category":"anthropic-skill","format":"markdown","content":"---\nname: relay-performance\ndescription: >-\n  Performance best practices for Relay applications. Use when optimizing data\n  fetching, reducing re-renders, configuring caching, or improving time to first\n  meaningful paint. Covers query placement, @defer, pagination, fetch policies,\n  garbage collection, fragment granularity, and server-side filtering. Companion\n  to the relay-best-practices skill which covers correctness and architecture.\n---\n\n# Relay Performance Best Practices\n\nPerformance-focused guidance for Relay applications. For correctness, naming,\nand architectural patterns, see the `relay-best-practices` skill.\n\nFor detailed API documentation, read the relevant page from `<llm-docs>/`\n(available in `node_modules/relay-runtime/llm-docs/` after v20.1.1).\n\n## One Query Per Screen\n\nEach screen or route should have **one** (or very few) root queries. Relay\ncoalesces all fragment data needs into a single network request per query.\nMultiple root queries on the same screen defeat this optimization — the browser\nmakes multiple parallel requests that each carry redundant overhead (HTTP\nheaders, connection setup, response parsing).\n\n```\nGOOD:                              BAD:\nRoute → 1 query                    Route → 3 queries\n  ├─ Header (fragment)               ├─ Header (query #1)\n  ├─ Content (fragment)               ├─ Content (query #2)\n  └─ Sidebar (fragment)               └─ Sidebar (query #3)\n```\n\n## Preload Before Rendering the Root\n\nFetch the initial query **before** calling `createRoot().render()`. This\noverlaps the network request with React's initialization, minimizing time to\nfirst meaningful paint.\n\n```tsx\n// Start fetch immediately — before React even initializes\nconst queryRef = loadQuery(environment, AppQuery, initialVariables);\n\n// Then render — data may already be available\nconst root = createRoot(document.getElementById('root'));\nroot.render(\n  <RelayEnvironmentProvider environment={environment}>\n    <Suspense fallback={<AppSkeleton />}>\n      <App queryRef={queryRef} />\n    </Suspense>\n  </RelayEnvironmentProvider>\n);\n```\n\n## Use `@defer` for Non-Critical Content\n\nDefer secondary or below-the-fold content so primary UI renders faster.\nRelay streams deferred data progressively via Suspense — the initial response\narrives smaller and the critical path renders sooner.\n\n```graphql\nquery ProfileScreenQuery($id: ID!) {\n  user(id: $id) {\n    ...ProfileHeader_user\n    ...ProfileDetails_user @defer\n    ...ProfileComments_user @defer\n  }\n}\n```\n\n```tsx\nfunction ProfileScreen({ queryRef }) {\n  const data = usePreloadedQuery(ProfileScreenQuery, queryRef);\n\n  return (\n    <ScrollView>\n      <ProfileHeader user={data.user} />\n      <Suspense fallback={<DetailsSkeleton />}>\n        <ProfileDetails user={data.user} />\n      </Suspense>\n      <Suspense fallback={<CommentsSkeleton />}>\n        <ProfileComments user={data.user} />\n      </Suspense>\n    </ScrollView>\n  );\n}\n```\n\nGood candidates for `@defer`:\n- Sidebar content\n- Below-the-fold sections\n- Tabs and accordions not visible on initial load\n- Heavy item details in paginated lists\n\n## Fetch Policies\n\n`store-or-network` (the default) is correct for most cases — it reuses cached\ndata and only hits the network for missing or stale data.\n\n| Policy | When to use |\n|--------|-------------|\n| `store-or-network` | Default. Best balance of speed and freshness. |\n| `store-and-network` | Show cached data immediately, update in background. |\n| `network-only` | Freshness is critical (e.g., after a mutation with wide side effects). |\n| `store-only` | Offline-first or reading data already guaranteed to be in the store. |\n\nReserve `network-only` for rare cases. Overusing it turns Relay into a\nno-cache client and eliminates the benefit of the normalized store.\n\n## Configure Garbage Collection\n\nSet `gcReleaseBufferSize` on the Relay Store to retain recently-used queries\nafter their components unmount. The default is 10. This makes navigating back\nto a previously visited screen instant (data is still in the store) instead of\ntriggering a new network request.\n\n```tsx\nconst store = new Store(new RecordSource(), {\n  gcReleaseBufferSize: 20,\n});\n```\n\nFor apps with many screens or heavy navigation, increase the buffer. For\nmemory-constrained environments (mobile), keep it conservative.\n\n## Filter and Sort on the Server\n\nUse GraphQL field arguments to filter and sort data on the server rather than\nfetching everything and processing in JavaScript.\n\n```tsx\n// BAD: fetch all tasks, filter on client\nconst data = useFragment(graphql`\n  fragment TaskList_user on User {\n    tasks { id, title, status }\n  }\n`, user);\nconst active = data.tasks.filter(t => t.status === 'ACTIVE');\n\n// GOOD: filter on server via field argument\nconst data = useFragment(graphql`\n  fragment TaskList_user on User {\n    tasks(status: ACTIVE) { id, title }\n  }\n`, user);\n```\n\nServer-side filtering reduces payload size, avoids unnecessary network\ntransfer, and reduces memory usage on the client.\n\n## Never Fetch Unbounded Collections\n\nAlways paginate list fields using `@connection` + `usePaginationFragment`.\nFetching an entire collection at once risks transferring megabytes of data,\nstalling the UI during normalization, and exhausting device memory.\n\nStart with a page size appropriate for the viewport (e.g., 10–20 items) and\nload more on scroll.\n\n```graphql\n# BAD: fetches every item — unbounded\nfragment NotificationList_user on User {\n  notifications {\n    id\n    message\n  }\n}\n\n# GOOD: paginated with a bounded first page\nfragment NotificationList_user on User\n  @argumentDefinitions(\n    count: { type: \"Int\", defaultValue: 10 }\n    cursor: { type: \"String\" }\n  )\n  @refetchable(queryName: \"NotificationListPaginationQuery\") {\n  notifications(first: $count, after: $cursor)\n    @connection(key: \"NotificationList_notifications\") {\n    edges {\n      node {\n        id\n        message\n      }\n    }\n  }\n}\n```\n\n## Keep Fragments Granular\n\nSplit large fragments into smaller, component-scoped fragments so Relay can\nre-render **only** the components whose data actually changed. A single\nmonolithic fragment shared by many components causes all of them to re-render\nwhen any field in the fragment changes.\n\n```tsx\n// BAD: one large fragment, all children re-render on any field change\nfunction PostCard({ post }) {\n  const data = useFragment(graphql`\n    fragment PostCard_post on Post {\n      title\n      body\n      author { name, profilePicture { uri } }\n      likeCount\n      commentCount\n    }\n  `, post);\n  return (\n    <>\n      <PostHeader title={data.title} author={data.author} />\n      <PostBody body={data.body} />\n      <PostFooter likes={data.likeCount} comments={data.commentCount} />\n    </>\n  );\n}\n\n// GOOD: each child owns its fragment, re-renders independently\nfunction PostHeader({ post }: { post: PostHeader_post$key }) {\n  const data = useFragment(graphql`\n    fragment PostHeader_post on Post {\n      title\n      author { name }\n    }\n  `, post);\n  // Only re-renders when title or author.name changes\n}\n\nfunction PostFooter({ post }: { post: PostFooter_post$key }) {\n  const data = useFragment(graphql`\n    fragment PostFooter_post on Post {\n      likeCount\n      commentCount\n    }\n  `, post);\n  // Only re-renders when like/comment counts change\n}\n```\n\n## One Connection Per Component\n\nUse a single `usePaginationFragment` per component. Multiple connections in\none component make pagination state harder to reason about — cursor tracking,\nloading states, and `hasNext` flags become tangled. Split each connection into\nits own component instead.\n\n## Avoid Unnecessary Refetches\n\nAfter a mutation, let Relay's normalized store auto-update components by\nspreading relevant fragments in the mutation response. Do not call `refetch()`\nor `fetchQuery()` when the store update is sufficient.\n\n```graphql\n# GOOD: updated data comes back with the mutation response\nmutation UpdateUserMutation($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    user {\n      ...UserProfile_user\n      ...UserAvatar_user\n    }\n  }\n}\n\n# BAD: requires a separate round-trip after mutation\nmutation UpdateUserMutation($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    user { id }\n  }\n}\n```\n\nUse `fetchKey` sparingly — changing it forces a full network round trip.\nReserve `refetchQueries` / manual refetch for cases where the mutation's side\neffects are too broad to capture in the response payload.\n\n## Fetch Only What You Need\n\nEach fragment should request only the fields the component actually renders.\nDo not add fields \"just in case\" — unused fields increase payload size and slow\ndown parsing and normalization. Relay's `unused-fields` lint rule catches this.\n\nIf a child component needs more data, add a fragment **to the child** and\nspread it in the parent — do not widen the parent's fragment.\n","frontmatter":{"name":"relay-performance","description":"Performance best practices for Relay applications. Use when optimizing data fetching, reducing re-renders, configuring caching, or improving time to first meaningful paint. Covers query placement, @defer, pagination, fetch policies, garbage collection, fragment granularity, and server-side filtering. Companion to the relay-best-practices skill which covers correctness and architecture."},"isInternal":false,"tokens":1974,"sizeBytes":8867},{"name":"README.md","path":"packages/babel-plugin-relay/README.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/babel-plugin-relay/README.md","title":"babel-plugin-relay Documentation","category":"plugin-manifest","format":"markdown","content":"## babel-plugin-relay\n\nRelay requires a Babel plugin to convert GraphQL tags to runtime artifacts.\n\nA _very_ simplified example of what this plugin is doing:\n\n```js\n// It converts this code\nconst fragment = graphql`\n  fragment User_fragment on User {\n    name\n  }\n`;\n\n// To require generated ASTs for fragments and queries\nconst fragment = require('__generated__/User_fragment.graphql');\n```\n\n## Plugin Configuration\n\n`babel-plugin-relay` will discover the config if:\n\n- There is a `relay.config.json`, `relay.config.js` file at the root of the\n  project (i.e. in the same folder as the `package.json` file).\n- The `package.json` file contains a `\"relay\"` key.\n\n> [!IMPORTANT]\n> This Babel plugin does not support `relay.config.mjs` or `package.json` with `\"type\": \"module\"`.\n\n### Supported configuration options for `babel-plugin-relay`\n\n- `artifactDirectory` A specific directory to output all artifacts to. When\n  enabling this the babel plugin needs `artifactDirectory` to be set as well.\n  [string]\n- `eagerEsModules` This option enables emitting ES modules artifacts.\n  [boolean][default: false]\n- `codegenCommand` The command to run to compile Relay files. [string]\n- `isDevVariableName` Name of the global variable for dev mode (e.g. `__DEV__`).\n  [string]\n- `jsModuleFormat` Formatting style for generated files. `commonjs` or `haste`.\n  Default is `commonjs`. [string]\n\n[Configuration Instructions](https://relay.dev/docs/getting-started/installation-and-setup/#set-up-babel-plugin-relay)\n","isInternal":false,"tokens":361,"sizeBytes":1499},{"name":"README.md","path":"packages/eslint-plugin-relay-internal/README.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/eslint-plugin-relay-internal/README.md","title":"eslint-plugin-relay-internal Documentation","category":"plugin-manifest","format":"markdown","content":"# eslint-plugin-relay-internal\n\nESLint rules intended to run on Relay's own codebase.\n","isInternal":false,"tokens":21,"sizeBytes":86},{"name":"README.md","path":"packages/react-relay/README.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/react-relay/README.md","title":"react-relay Documentation","category":"plugin-manifest","format":"markdown","content":"## React APIs for Relay\n\nThis package contains a collection of React APIs: Hooks and Components that are\nintegrated with Relay runtime.\n\nExample:\n\n```js\n// @flow\n\nimport type {UserComponent_user$key} from 'UserComponent_user.graphql';\n\nconst React = require('react');\n\nconst {graphql, useFragment} = require('react-relay');\n\ntype Props = {\n  user: UserComponent_user$key,\n};\n\nfunction UserComponent(props: Props) {\n  const data = useFragment(\n    graphql`\n      fragment UserComponent_user on User {\n        name\n        profile_picture(scale: 2) {\n          uri\n        }\n      }\n    `,\n    props.user,\n  );\n\n  return (\n    <>\n      <h1>{data.name}</h1>\n      <div>\n        <img src={data.profile_picture?.uri} />\n      </div>\n    </>\n  );\n}\n```\n\nFor complete API reference, visit https://relay.dev/.\n","isInternal":false,"tokens":193,"sizeBytes":802},{"name":"README.md","path":"packages/relay-compiler/README.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-compiler/README.md","title":"relay-compiler Documentation","category":"plugin-manifest","format":"markdown","content":"# Relay Compiler\n\nSee https://relay.dev/docs/next/guides/compiler/\n","isInternal":false,"tokens":17,"sizeBytes":67},{"name":"README.md","path":"packages/relay-e2e-test/README.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/README.md","title":"relay-e2e-test Documentation","category":"plugin-manifest","format":"markdown","content":"# relay-e2e-test Documentation\n\nPath: `packages/relay-e2e-test/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/README.md)","tokens":300,"sizeBytes":192},{"name":"README.md","path":"packages/relay-runtime/README.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-runtime/README.md","title":"relay-runtime Documentation","category":"plugin-manifest","format":"markdown","content":"# relay-runtime Documentation\n\nPath: `packages/relay-runtime/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-runtime/README.md)","tokens":300,"sizeBytes":189},{"name":"README.md","path":"packages/relay-test-utils-internal/README.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils-internal/README.md","title":"relay-test-utils-internal Documentation","category":"plugin-manifest","format":"markdown","content":"# relay-test-utils-internal Documentation\n\nPath: `packages/relay-test-utils-internal/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils-internal/README.md)","tokens":300,"sizeBytes":225},{"name":"README.md","path":"packages/relay-test-utils/README.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils/README.md","title":"relay-test-utils Documentation","category":"plugin-manifest","format":"markdown","content":"# relay-test-utils Documentation\n\nPath: `packages/relay-test-utils/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-test-utils/README.md)","tokens":300,"sizeBytes":198},{"name":"fix-ci.md","path":".claude/commands/fix-ci.md","rawUrl":"https://raw.githubusercontent.com/facebook/relay/HEAD/.claude/commands/fix-ci.md","title":"Command: /fix-ci","category":"command-prompt","format":"markdown","content":"# Fix CI Skill\n\nYou are a specialized skill for checking GitHub CI status and fixing failing tests in the Relay project.\n\n## Your Task\n\n1. **Check Current CI Status**\n   - Use `gh run list --branch=main --workflow=ci.yml --limit 5` to see recent workflow runs\n   - If the most recent run is failing, use `gh run view <ID>` using the ID from the most recent run to get detailed status\n   - Identify any failing jobs or checks\n\n2. **Analyze Failures**\n   - For each failing job, use `gh run view <run-id> --log-failed` to get failure logs\n   - **Note**: If this command has no output, you may need to upgrade `gh`. See https://github.com/cli/cli/issues/10551.\n   - Parse the logs to identify the specific test failures or errors\n\n3. **Fix the Issues**\n   - Based on the failure type, take appropriate action:\n   - See `CONTRIBUTING.md` for instructions on how to work in this repository.\n\n   ### Special Case: Out-of-date Cargo.lock\n\n   If the failure is related to an out-of-date `Cargo.lock` file (look for errors like \"the lock file needs to be updated but --locked was passed\" or diffs showing changes to Cargo.lock), it cannot be fixed in this repository.\n\n   `compiler/Cargo.lock` is generated from Meta's internal monorepo and synced here, so a pull request editing it would be overwritten by the next sync.\n\n   1. **Report it**: Tell the user the lock file is stale and needs to be regenerated internally, then landed — it syncs here automatically afterwards.\n\n   2. **Do NOT manually update Cargo.lock**, and do not open a pull request against it.\n\n4. **Create a Pull Request**\n   - Create a new branch: `git checkout -b fix-ci-failures-$(date +%Y%m%d-%H%M%S)`\n   - Stage all changes: `git add .`\n   - Commit with descriptive message about what was fixed\n   - Push the branch: `git push -u origin HEAD`\n   - Create PR using `gh pr create` with:\n     - **IMPORTANT: Always include `--label \"Fix CI Skill\"` in the `gh pr create` command**\n     - Title: \"Fix CI failures - [Brief description]\"\n     - Body: Detailed explanation of:\n       - Which jobs were failing\n       - What the errors were\n       - How you fixed them\n       - Test results showing the fixes work\n\n5. **Monitor PR and Iterate Until Passing**\n   - After creating the PR, monitor the CI status in a loop\n   - Use `gh run list --branch=<your-branch> --limit 1` to check the latest run\n   - Use `gh run view <run-id>` to check if it's completed and its status\n   - If the run is still in progress, wait 30 seconds and check again\n   - If the run fails:\n     - Use `gh run view <run-id> --log-failed` to get failure logs\n     - Analyze the new failures (they may be different from the original ones)\n     - Fix the issues following the same process as step 3\n     - Commit and push the fixes: `git add . && git commit -m \"Fix additional CI failures\" && git push`\n     - Continue monitoring the new CI run\n   - Keep iterating until all CI checks pass\n   - Report success when all checks are green\n\n## Important Guidelines\n\n- Always verify fixes locally before creating a PR\n- If you can't automatically fix an issue, document it clearly in your response\n- Check if there are multiple failures - fix all of them in one PR if possible\n- Run the relevant test suite locally before pushing\n- Make sure your fixes don't introduce new issues\n- If CI is passing, report that and don't create unnecessary PRs\n\n## Example Workflow\n\n```bash\n# 1. Check CI status\ngh run list --branch=main --workflow=ci.yml --limit 5\n\n# 2. Get details of latest run\ngh run view 20949129659 --log-failed\n\n# 3. If JS tests are failing, run locally\nyarn run jest <failing-test>\n\n# 4. Fix the code\n# (Read files, make edits)\n\n# 5. Verify fix\nyarn run jest <failing-test>\n\n# 6. Create PR\ngit checkout -b fix-ci-failures-20260106\ngit add .\ngit commit -m \"Fix failing jest tests in MockPayloadGenerator\"\ngit push -u origin HEAD\ngh pr create --label \"Fix CI Skill\" --title \"Fix CI: MockPayloadGenerator test failures\" --body \"...\"\n```\n\n## Start Here\n\nBegin by checking the current CI status and reporting what you find.\n","isInternal":false,"tokens":1022,"sizeBytes":4055}],"systemPromptSnippet":"<yakaai_skills repo=\"facebook/relay\">\n<!-- File: packages/babel-plugin-relay/package.json (Tokens: ~234 | Category: anthropic-skill) -->\n{\n  \"name\": \"babel-plugin-relay\",\n  \"description\": \"A Babel Plugin for use with Relay applications.\",\n  \"version\": \"21.0.1\",\n  \"keywords\": [\n    \"graphql\",\n    \"relay\",\n    \"babel\",\n    \"babel-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/babel-plugin-relay\"\n  },\n  \"dependencies\": {\n    \"babel-plugin-macros\": \"^2.0.0\",\n    \"cosmiconfig\": \"^5.0.5\",\n    \"graphql\": \"17.0.2\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.25.2\",\n    \"prettier\": \"3.9.4\"\n  },\n  \"resolutions\": {\n    \"@babel/traverse\": \"^7.23.2\"\n  }\n}\n\n<!-- File: packages/eslint-plugin-relay-internal/package.json (Tokens: ~215 | Category: anthropic-skill) -->\n{\n  \"name\": \"eslint-plugin-relay-internal\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"description\": \"ESLint rules intended to run on Relay's own codebase\",\n  \"keywords\": [\n    \"eslint\",\n    \"eslintplugin\",\n    \"eslint-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/relay-test-utils-internal\"\n  },\n  \"main\": \"./lib/index.js\",\n  \"exports\": \"./lib/index.js\",\n  \"dependencies\": {},\n  \"engines\": {\n    \"node\": \"^14.17.0 || ^16.0.0 || >= 18.0.0\"\n  },\n  \"peerDependencies\": {\n    \"eslint\": \">=7\"\n  }\n}\n\n<!-- File: packages/react-relay/package.json (Tokens: ~257 | Category: anthropic-skill) -->\n{\n  \"name\": \"react-relay\",\n  \"description\": \"A framework for building GraphQL-driven React applications.\",\n  \"version\": \"21.0.1\",\n  \"keywords\": [\n    \"graphql\",\n    \"relay\",\n    \"react\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/react-relay\"\n  },\n  \"dependencies\": {\n    \"@babel/runtime\": \"^7.25.0\",\n    \"fbjs\": \"^3.0.2\",\n    \"invariant\": \"^2.2.4\",\n    \"nullthrows\": \"^1.1.1\",\n    \"relay-runtime\": \"21.0.1\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.9.0 || ^17 || ^18 || ^19\"\n  },\n  \"directories\": {\n    \"\": \"./\"\n  },\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"haste_commonjs\": true\n}\n\n<!-- File: packages/relay-compiler/package.json (Tokens: ~137 | Category: anthropic-skill) -->\n{\n  \"name\": \"relay-compiler\",\n  \"description\": \"A compiler tool for building GraphQL-driven applications.\",\n  \"version\": \"21.0.1\",\n  \"keywords\": [\n    \"graphql\",\n    \"relay\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://relay.dev\",\n  \"bugs\": \"https://github.com/facebook/relay/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/facebook/relay.git\",\n    \"directory\": \"packages/relay-compiler\"\n  },\n  \"main\": \"index.js\",\n  \"bin\": \"cli.js\"\n}\n\n<!-- File: packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-github.md (Tokens: ~300 | Category: anthropic-skill) -->\n# References Skill\n\nPath: `packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-github.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-github.md)\n\n<!-- File: packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-internal.md (Tokens: ~300 | Category: anthropic-skill) -->\n# References Skill\n\nPath: `packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-internal.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/running-tests-internal.md)\n\n<!-- File: packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/writing-fixtures.md (Tokens: ~300 | Category: anthropic-skill) -->\n# References Skill\n\nPath: `packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/writing-fixtures.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/.llms/skills/relay-e2e-test/references/writing-fixtures.md)\n\n<!-- File: packages/relay-e2e-test/.llms/skills/relay-e2e-test/SKILL.md (Tokens: ~318 | Category: anthropic-skill) -->\n---\nname: relay-e2e-test\ndescription: Write and run markdown-driven e2e tests for Relay. Covers fixture format, server/client code patterns, interaction DSL, snapshots, and running tests.\nallowed-tools: Bash, Read, Edit, Write, AskUserQuestion, mcp__plugin_meta_mux__search_files\nmetadata:\n  oncalls: ['relay']\n  strict: true\n---\n\n# Relay E2E Tests\n\nMarkdown-driven end-to-end tests for Relay. Each test is a self-contained `.md` file that defines a GraphQL server (via [Grats](https://grats.capt.dev/)), a Relay-powered React component, and optional interaction steps. The test harness extracts the code blocks, compiles them with Grats + relay-compiler, renders with React Testing Library, runs interactions, and snapshot-tests the output.\n\nTests run against **Relay runtime packages from source**, so changes are reflected immediately without a build step.\n\n## References\n\nRead the appropriate reference file based on your task:\n\n- **[Writing fixtures](references/writing-fixtures.md)** — fixture format, example, server/client code patterns, interaction DSL, snapshots. Read when creating or modifying test fixtures.\n- **[Running tests (internal)](references/running-tests-internal.md)** — setup, commands, and compiler resolution for fbsource / OD. Read when running tests internally.\n- **[Running tests (GitHub)](references/running-tests-github.md)** — setup, commands, and compiler resolution for the OSS repo. Read when running tests on GitHub.\n\n<!-- File: packages/relay-e2e-test/fixtures/data-driven-dependencies/module.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Data-driven-dependencies Skill\n\nPath: `packages/relay-e2e-test/fixtures/data-driven-dependencies/module.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/data-driven-dependencies/module.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/data-driven-dependencies/module.snap.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Data-driven-dependencies Skill\n\nPath: `packages/relay-e2e-test/fixtures/data-driven-dependencies/module.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/data-driven-dependencies/module.snap.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mixed-interface/nested-field.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/nested-field.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/nested-field.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mixed-interface/nested-field.snap.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/nested-field.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/nested-field.snap.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.snap.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mixed-interface Skill\n\nPath: `packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mixed-interface/server-and-resolver-type-share-interface.snap.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.snap.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-catch-field-error.snap.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.snap.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-field-errors.snap.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.snap.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-form-action.snap.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.snap.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-boundary.snap.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.snap.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-network-error-catch.snap.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.snap.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-optimistic.snap.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.snap.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-sequential.snap.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.md)\n\n<!-- File: packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.snap.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Mutations Skill\n\nPath: `packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.snap.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/facebook/relay/HEAD/packages/relay-e2e-test/fixtures/mutations/useMutationAction-top-level-field-error.snap.md)\n\n<!-- ... +24 more modular skills available via /api/skills/facebook/relay?path={path} -->\n</yakaai_skills>"}