Skip to content

Commit 8a51ea6

Browse files
phryneasclaude
andauthored
feat: add Apollo Client agent skill to repo (tanstack/intent + sync to apollographql/skills) (#13202)
Sister PR at apollographql/skills#52 ## Summary - Moves `docs/agent-skills/apollo-client/` (SKILL.md + 13 reference files) into this repo as the new source of truth, migrated from `apollographql/skills` - Copies the skill to `dist/skills/apollo-client/` during build so it ships inside the `@apollo/client` npm package, discoverable via the [tanstack/intent](https://tanstack.com/intent/latest/docs/getting-started/quick-start-maintainers) convention (`"tanstack-intent"` keyword in package.json) - Adds `.github/workflows/sync-skill.yml`: on push to `main` touching `docs/agent-skills/apollo-client/**`, dispatches `sync-apollo-client-skill.yml` in `apollographql/skills` (same pattern as `devtools-errorcodes.yml`) so that repo stays in sync **Note:** A counterpart workflow `sync-apollo-client-skill.yml` must be added to `apollographql/skills` before the sync trigger is live. That workflow receives the `source_sha` input, fetches the skill files from this repo at that SHA, and opens an auto-merging PR. Until that workflow exists, the dispatch step will fail silently. ## Test plan - [ ] Run `npm run build` and verify `dist/skills/apollo-client/SKILL.md` and `dist/skills/apollo-client/references/` are present - [ ] Run `npm pack --dry-run` from `dist/` and confirm skill files appear in the package manifest - [ ] Manually trigger the sync workflow via `workflow_dispatch` once the counterpart workflow in `apollographql/skills` is in place 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Documentation** * Added comprehensive Apollo Client reference documentation with integration guides for Next.js, React Router, TanStack Start, and client-side React applications * Added reference guides covering caching, error handling, fragments, mutations, queries, state management, Suspense hooks, TypeScript code generation, and troubleshooting * **Chores** * Updated package metadata and automated skill synchronization infrastructure <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: phryneas <4282439+phryneas@users.noreply.github.com>
1 parent 46a45c3 commit 8a51ea6

23 files changed

Lines changed: 6009 additions & 20 deletions

.agents/skills/apollo-client

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../docs/agent-skills/apollo-client

.changeset/tiny-numbers-double.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@apollo/client": patch
3+
---
4+
5+
Ship agent skill for usage with @tanstack/intent — the skill is now bundled in the npm package under `skills/apollo-client/` and discoverable by `intent list`.
6+
For more context, see the [TanStack Intent QuickStart](https://tanstack.com/intent/latest/docs/getting-started/quick-start-consumers).

.claude/skills

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../.agents/skills

.github/workflows/copilot-setup-steps.yml

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,11 @@ jobs:
4545
uses: actions/cache@v5
4646
with:
4747
path: |
48-
.agents/skills/apollo-client/
49-
.github/skills/apollo-client/
5048
.github/instructions/docs.instructions.md
5149
key: skills-${{ steps.skills-head.outputs.sha }}
5250
restore-keys: |
5351
skills-
5452
55-
- name: Install JavaScript dependencies (with cache)
56-
uses: bahmutov/npm-install@v1
57-
58-
- name: Install Apollo Client Skill
59-
if: steps.cache-skills.outputs.cache-hit != 'true'
60-
run: |
61-
echo "Installing Apollo Client skill using npx skills CLI"
62-
npx --yes skills add apollographql/skills --skill apollo-client --agent github-copilot --scope project --method copy --yes
63-
echo "Apollo Client skill installed successfully"
64-
6553
- name: Copy Documentation Instructions
6654
if: steps.cache-skills.outputs.cache-hit != 'true'
6755
run: |

.github/workflows/sync-skill.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Sync agent skill to apollographql/skills
2+
on:
3+
push:
4+
branches: [main]
5+
paths:
6+
- "docs/agent-skills/apollo-client/**"
7+
workflow_dispatch: # for testing
8+
permissions: {}
9+
jobs:
10+
dispatch:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/create-github-app-token@v1
14+
id: github-actions-bot-app-token
15+
with:
16+
app-id: 819772
17+
private-key: ${{ secrets.APOLLO_GITHUB_ACTIONS_BOT_PRIVATE_KEY }}
18+
repositories: skills
19+
- uses: benc-uk/workflow-dispatch@v1
20+
with:
21+
workflow: sync-apollo-client-skill.yml
22+
repo: apollographql/skills
23+
token: ${{ steps.github-actions-bot-app-token.outputs.token }}
24+
inputs: '{"source_sha": "${{ github.sha }}"}'

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# Installed via Github Copilot Setup Steps, should not be committed
2-
.agents/skills/apollo-client
32
.github/instructions/docs.instructions.md
4-
.github/skills/apollo-client
53

64
# fs
75
.DS_Store

.size-limits.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (CJS)": 46917,
3-
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production) (CJS)": 41535,
4-
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\"": 35552,
5-
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production)": 29305
2+
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (CJS)": 46884,
3+
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production) (CJS)": 41517,
4+
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\"": 35542,
5+
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production)": 29276
66
}

config/prepareDist.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
// - Create a new `package.json` for each sub-set bundle we support, and
1212
// store it in the appropriate dist sub-directory.
1313

14-
import { copyFile, mkdir } from "node:fs/promises";
14+
import { copyFile, cp, mkdir } from "node:fs/promises";
1515
import { join } from "node:path";
1616

1717
import type { BuildStep } from "./build.ts";
@@ -75,4 +75,11 @@ export const prepareDist: BuildStep = async (options) => {
7575
`${options.rootDir}/CHANGELOG.md`,
7676
`${options.packageRoot}/CHANGELOG.md`
7777
);
78+
79+
// Copy agent skill into "dist/skills/apollo-client" for tanstack/intent npm discovery
80+
await cp(
81+
join(options.rootDir, "docs/agent-skills/apollo-client"),
82+
join(options.packageRoot, "skills/apollo-client"),
83+
{ recursive: true }
84+
);
7885
};
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
---
2+
name: apollo-client
3+
description: >
4+
Guide for building React applications with Apollo Client 4.x. Use this skill when:
5+
(1) setting up Apollo Client in a React project,
6+
(2) writing GraphQL queries or mutations with hooks,
7+
(3) configuring caching or cache policies,
8+
(4) managing local state with reactive variables,
9+
(5) troubleshooting Apollo Client errors or performance issues.
10+
license: MIT
11+
compatibility: React 18+, React 19 (Suspense/RSC). Works with Next.js, Vite, CRA, and other React frameworks.
12+
metadata:
13+
author: apollographql
14+
version: "1.0.0"
15+
allowed-tools: Bash(npm:*) Bash(npx:*) Bash(node:*) Read Write Edit Glob Grep
16+
---
17+
18+
# Apollo Client 4.x Guide
19+
20+
Apollo Client is a comprehensive state management library for JavaScript that enables you to manage both local and remote data with GraphQL. Version 4.x brings improved caching, better TypeScript support, and React 19 compatibility.
21+
22+
## Integration Guides
23+
24+
Choose the integration guide that matches your application setup:
25+
26+
- **[Client-Side Apps](references/integration-client.md)** - For client-side React applications without SSR (Vite, Create React App, etc.)
27+
- **[Next.js App Router](references/integration-nextjs.md)** - For Next.js applications using the App Router with React Server Components
28+
- **[React Router Framework Mode](references/integration-react-router.md)** - For React Router 7 applications with streaming SSR
29+
- **[TanStack Start](references/integration-tanstack-start.md)** - For TanStack Start applications with modern routing
30+
31+
Each guide includes installation steps, configuration, and framework-specific patterns optimized for that environment.
32+
33+
## Quick Reference
34+
35+
### Basic Query
36+
37+
```tsx
38+
import { gql } from "@apollo/client";
39+
import { useQuery } from "@apollo/client/react";
40+
41+
const GET_USER = gql`
42+
query GetUser($id: ID!) {
43+
user(id: $id) {
44+
id
45+
name
46+
}
47+
}
48+
`;
49+
50+
function UserProfile({ userId }: { userId: string }) {
51+
const { loading, error, data, dataState } = useQuery(GET_USER, {
52+
variables: { id: userId },
53+
});
54+
55+
if (loading) return <p>Loading...</p>;
56+
if (error) return <p>Error: {error.message}</p>;
57+
58+
// TypeScript: dataState === "ready" provides better type narrowing than just checking data
59+
return <div>{data.user.name}</div>;
60+
}
61+
```
62+
63+
### Basic Mutation
64+
65+
```tsx
66+
import { gql } from "@apollo/client";
67+
import { useMutation } from "@apollo/client/react";
68+
69+
const CREATE_USER = gql`
70+
mutation CreateUser($input: CreateUserInput!) {
71+
createUser(input: $input) {
72+
id
73+
name
74+
}
75+
}
76+
`;
77+
78+
function CreateUserForm() {
79+
const [createUser, { loading, error }] = useMutation(CREATE_USER);
80+
81+
const handleSubmit = async (name: string) => {
82+
await createUser({ variables: { input: { name } } });
83+
};
84+
85+
return <button onClick={() => handleSubmit("John")}>Create User</button>;
86+
}
87+
```
88+
89+
### Suspense Query
90+
91+
```tsx
92+
import { Suspense } from "react";
93+
import { useSuspenseQuery } from "@apollo/client/react";
94+
95+
function UserProfile({ userId }: { userId: string }) {
96+
const { data } = useSuspenseQuery(GET_USER, {
97+
variables: { id: userId },
98+
});
99+
100+
return <div>{data.user.name}</div>;
101+
}
102+
103+
function App() {
104+
return (
105+
<Suspense fallback={<p>Loading user...</p>}>
106+
<UserProfile userId="1" />
107+
</Suspense>
108+
);
109+
}
110+
```
111+
112+
## Reference Files
113+
114+
Detailed documentation for specific topics:
115+
116+
- [TypeScript Code Generation](references/typescript-codegen.md) - GraphQL Code Generator setup for type-safe operations
117+
- [Queries](references/queries.md) - useQuery, useLazyQuery, polling, refetching
118+
- [Suspense Hooks](references/suspense-hooks.md) - useSuspenseQuery, useBackgroundQuery, useReadQuery, useLoadableQuery
119+
- [Mutations](references/mutations.md) - useMutation, optimistic UI, cache updates
120+
- [Fragments](references/fragments.md) - Fragment colocation, useFragment, useSuspenseFragment, data masking
121+
- [Caching](references/caching.md) - InMemoryCache, typePolicies, cache manipulation
122+
- [State Management](references/state-management.md) - Reactive variables, local state
123+
- [Error Handling](references/error-handling.md) - Error policies, error links, retries
124+
- [Troubleshooting](references/troubleshooting.md) - Common issues and solutions
125+
126+
## Key Rules
127+
128+
### Query Best Practices
129+
130+
- **Each page should generally only have one query, composed from colocated fragments.** Use `useFragment` or `useSuspenseFragment` in all non-page-components. Use `@defer` to allow slow fields below the fold to stream in later and avoid blocking the page load.
131+
- **Fragments are for colocation, not reuse.** Each fragment should describe exactly the data needs of a specific component, not be shared across components for common fields. See [Fragments reference](references/fragments.md) for details on fragment colocation and data masking.
132+
- Always handle `loading` and `error` states in UI when using non-suspenseful hooks (`useQuery`, `useLazyQuery`). When using Suspense hooks (`useSuspenseQuery`, `useBackgroundQuery`), React handles this through `<Suspense>` boundaries and error boundaries.
133+
- Use `fetchPolicy` to control cache behavior per query
134+
- Use the TypeScript type server to look up documentation for functions and options (Apollo Client has extensive docblocks)
135+
136+
### Mutation Best Practices
137+
138+
- **If the schema permits, mutation return values should return everything necessary to update the cache.** Neither manual updates nor refetching should be necessary.
139+
- If the mutation response is insufficient, carefully weigh manual cache manipulation vs refetching. Manual updates risk missing server logic. Consider optimistic updates with a granular refetch if needed.
140+
- Handle errors gracefully in the UI
141+
- Use `refetchQueries` sparingly (prefer letting the cache update automatically)
142+
143+
### Caching Best Practices
144+
145+
- Configure `keyFields` for types without `id` field
146+
- Disable normalization by setting `keyFields: false` for types that don't include an identifier and are meant to group related fields under the parent
147+
- Use `typePolicies` for pagination and computed fields
148+
- Understand cache normalization to debug issues
149+
- **Enable [data masking](references/fragments.md#data-masking) for all new applications** - it prevents components from accessing fragment data they don't own, enforcing proper data boundaries and preventing over-rendering
150+
151+
### Performance
152+
153+
- Avoid over-fetching with proper field selection
154+
- Configure appropriate `fetchPolicy` per use case
155+
- Use `@defer` for incremental delivery of deferred query parts, and `@stream` for streaming list fields (`@stream` available in Apollo Client 4.1+)
156+
- **Prefer Suspense hooks (`useSuspenseQuery`, `useBackgroundQuery`) in modern applications** for better loading state handling and code simplicity
157+
158+
## Ground Rules
159+
160+
- ALWAYS use Apollo Client 4.x patterns (not v3 or earlier)
161+
- ALWAYS wrap your app with `ApolloProvider`
162+
- ALWAYS handle loading and error states when using non-suspenseful hooks
163+
- PREFER Suspense hooks (`useSuspenseQuery`, `useBackgroundQuery`) in modern applications for better DX
164+
- NEVER store Apollo Client in React state (use module-level or context)
165+
- PREFER `cache-first` for read-heavy data, `network-only` for real-time data
166+
- USE TypeScript for better type safety with GraphQL
167+
- IMPLEMENT proper cache updates instead of refetching entire queries
168+
- ADVISE the human steering you to look into Apollo DevTools when collaboratively debugging Apollo Client issues

0 commit comments

Comments
 (0)