Shopify Expert
Jeffallan/claude-skills
Builds Shopify themes in Liquid, custom apps, Storefront API storefronts and checkout extensions, using the Shopify CLI to lint, run locally and deploy.
Best practices for writing idiomatic Relay code. An agent skill from hackers-pub/hackerspub.
$ npx skills add hackers-pub/hackerspub --skill relay-best-practices -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install hackers-pub/hackerspub relay-best-practices --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/hackers-pub/hackerspub.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/relay-best-practices .claude/skills/relay-best-practices && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "relay-best-practices" agent skill from https://github.com/hackers-pub/hackerspub/tree/main/.agents/skills/relay-best-practices into .claude/skills/relay-best-practices/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "relay-best-practices", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/hackers-pub/hackerspub/tree/main/.agents/skills/relay-best-practicesType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add hackers-pub/hackerspub --skill relay-best-practices -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install hackers-pub/hackerspub relay-best-practices --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/hackers-pub/hackerspub.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/relay-best-practices .agents/skills/relay-best-practices && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "relay-best-practices" agent skill from https://github.com/hackers-pub/hackerspub/tree/main/.agents/skills/relay-best-practices into .agents/skills/relay-best-practices/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "relay-best-practices", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add hackers-pub/hackerspub --skill relay-best-practices -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install hackers-pub/hackerspub relay-best-practices --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/hackers-pub/hackerspub.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/relay-best-practices .cursor/skills/relay-best-practices && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "relay-best-practices" agent skill from https://github.com/hackers-pub/hackerspub/tree/main/.agents/skills/relay-best-practices into .cursor/skills/relay-best-practices/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "relay-best-practices", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/hackers-pub/hackerspub.git --path .agents/skills/relay-best-practices--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add hackers-pub/hackerspub --skill relay-best-practices -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install hackers-pub/hackerspub relay-best-practices --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/hackers-pub/hackerspub.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/relay-best-practices .gemini/skills/relay-best-practices && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "relay-best-practices" agent skill from https://github.com/hackers-pub/hackerspub/tree/main/.agents/skills/relay-best-practices into .gemini/skills/relay-best-practices/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "relay-best-practices", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install hackers-pub/hackerspub relay-best-practicesInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add hackers-pub/hackerspub --skill relay-best-practices -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/hackers-pub/hackerspub.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/relay-best-practices .github/skills/relay-best-practices && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "relay-best-practices" agent skill from https://github.com/hackers-pub/hackerspub/tree/main/.agents/skills/relay-best-practices into .github/skills/relay-best-practices/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "relay-best-practices", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add hackers-pub/hackerspub --skill relay-best-practices -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install hackers-pub/hackerspub relay-best-practices --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/hackers-pub/hackerspub.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/relay-best-practices .opencode/skills/relay-best-practices && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "relay-best-practices" agent skill from https://github.com/hackers-pub/hackerspub/tree/main/.agents/skills/relay-best-practices into .opencode/skills/relay-best-practices/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "relay-best-practices", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
relay-best-practicesBest practices for writing idiomatic Relay code. An agent skill from hackers-pub/hackerspub.
Relay Best Practices is an agent skill from hackers-pub/hackerspub. 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.
Its SKILL.md is about 4.6k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Backend & APIs, covering GraphQL and React components. It works with GraphQL and React. The repository describes itself as: ActivityPub-enabled social network for hackers. The licence is AGPL-3.0.
Read from SKILL.md and the folder at commit 45b039b. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
npxyarnFrom the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
raw.githubusercontent.comFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Relay Best Practices loads about 4.6k tokens when it runs. Until then it costs about 134 tokens; SKILL.md has 2,028 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from hackers-pub/hackerspub at commit 45b039b, republished under its AGPL-3.0 licence (© hackers-pub). 2,028 words, ~4,604 tokens.
.claude/skills/relay-best-practices/SKILL.md (or your agent's skills folder).Relay is a GraphQL client for React that enforces colocated, composable, and type-safe data fetching. Its core insight is that each component should declare exactly what data it needs via GraphQL fragments, and Relay handles the rest — fetching, caching, consistency, and updates.
This skill provides opinionated guidance on which patterns to prefer. For detailed API documentation, read the relevant page from the doc map below.
Relay ships LLM-friendly docs in node_modules/relay-runtime/llm-docs/
(available after v20.1.1). For older versions, fetch the same files from
https://raw.githubusercontent.com/facebook/relay/main/website/docs/.
Paths below are relative to this directory (<llm-docs>/). Read the relevant
page before writing Relay code. Key docs:
| Topic | Path |
|---|---|
| Core concepts & philosophy | principles-and-architecture/thinking-in-relay.mdx |
| Fragments | guided-tour/rendering/fragments.mdx |
| Queries | guided-tour/rendering/queries.mdx |
| Mutations | guided-tour/updating-data/graphql-mutations.mdx |
| Pagination | guided-tour/list-data/pagination.mdx |
| Refetching | guided-tour/refetching/refetching-queries-with-different-data.mdx |
useFragment | api-reference/hooks/use-fragment.mdx |
usePreloadedQuery | api-reference/hooks/use-preloaded-query.mdx |
useQueryLoader / loadQuery | api-reference/hooks/load-query.mdx |
useMutation | api-reference/hooks/use-mutation.mdx |
usePaginationFragment | api-reference/hooks/use-pagination-fragment.mdx |
@throwOnFieldError | guides/throw-on-field-error-directive.mdx |
@catch directive | guides/catch-directive.mdx |
| Semantic nullability | guides/semantic-nullability.mdx |
| Relay Resolvers | guides/relay-resolvers/introduction.mdx |
| Testing | guides/testing-relay-components.mdx |
| Compiler setup | getting-started/compiler.mdx |
| Compiler configuration | getting-started/compiler-config.mdx |
| Lint rules (ESLint plugin) | getting-started/lint-rules.mdx |
For performance-specific guidance (query placement, @defer, pagination,
fetch policies, caching, fragment granularity), see the companion
relay-performance skill.
These principles are the foundation of every decision below. When in doubt, refer back to them.
Relay uses an ahead-of-time compiler that reads graphql tagged template
literals in your code and generates runtime artifacts and TypeScript/Flow types.
The compiler looks for its config in these locations (checked in order):
relay.config.{json,js,mjs,ts} in the project root"relay" key in package.jsonSee <llm-docs>/getting-started/compiler-config.mdx for the full config schema.
You can also emit a JSON Schema for the config by running
npx relay-compiler config-json-schema.
Run npx relay-compiler after any change to the contents of a graphql tagged
template literal or the docblock of a Relay Resolver. Some projects add this as
a script in package.json (e.g., yarn relay). The compiler also supports watch mode (--watch), but avoid using it in
non-interactive contexts since the process never exits.
Generated files go into __generated__/ directories next to the source files.
Never edit these files — they are overwritten on every compiler run. If you see
type errors about missing generated types, run the compiler first — the
types are likely just out of date.
Relay's ESLint plugin (eslint-plugin-relay) is a key part of the developer
experience. Two rules are especially important:
relay/unused-fields — detects GraphQL fields that are selected in a
fragment but never read in the component. This prevents the "append-only
query" problem where fragments accumulate unused fields over time, fetching
data no component actually needs.relay/no-future-added-value — prevents explicitly handling the
"%future added value" enum placeholder that Relay inserts to ensure you
handle the possibility of new enum variants being added by the server.See <llm-docs>/getting-started/lint-rules.mdx for installation and configuration.
Queries belong at route entrypoints (the top-level component for a URL).
Hooks are leaves — reused across many components. A query inside a hook fires
late (after the hook's host renders) AND duplicates across every caller. The fix
is always: accept a fragment key as a parameter, use useFragment.
Use usePreloadedQuery + useQueryLoader (or loadQuery). Start the fetch in
an event handler, route transition, or during app initialization — before the
component renders. useLazyLoadQuery does not start fetching until render,
creating waterfalls. See <llm-docs>/guided-tour/rendering/queries.mdx for the full pattern.
| Question | If YES |
|---|---|
| Parent already fetches this GraphQL type? | Delete query, use useFragment |
| Component only fetches and passes data down? | Delete the wrapper component entirely (loader anti-pattern) |
| Query is inside a custom hook? | Delete query, accept a fragment key param |
| Two components fetch the same data? | Delete one query, fetch in a common ancestor |
| Data is only used for logging/analytics? | Move to @defer or server-side logging |
| Data is static config (same for every user)? | Inject server-side, no round-trip needed |
loadQuery in useEffect is worse than useLazyLoadQueryuseEffect runs after paint, so the fetch starts even later than
useLazyLoadQuery (which at least starts during render). Call loadQuery in
event handlers, route transitions, or app initialization — never in effects.
useFragmentWhen deciding whether useFragment can replace a query, walk up the
component tree from your component. Stop at: route boundaries, feature gates,
conditional renders, or user-triggered interactions. Keep walking through:
unconditional renders, layout/wrapper components, context providers.
If any ancestor already queries the GraphQL type you need, useFragment is
the answer. Threading fragment keys through several layers of props is fine —
it IS the correct pattern.
Never default a query variable to '', 0, or null when the real value is
unavailable. This fires the query with bad data, returning wrong results or
errors. Instead, use conditional rendering (if (!id) return null) or
@include/@skip directives to omit the field entirely.
Every component that displays server data should declare a fragment and receive
a fragment reference (the $key type) as a prop. The parent spreads the
child's fragment in its own query or fragment and passes the result down. See
the "Maintain fragment co-location" anti-pattern below for an example.
Spread the consuming component's fragment into the mutation response rather than selecting fields individually. This keeps them in sync automatically. See the anti-pattern example below.
@throwOnFieldError and @catchThe recommended approach for handling field errors and nullability is to add
@throwOnFieldError to your fragment or query. This causes Relay to throw a
JavaScript exception if a field error is encountered, which can be caught by a
React error boundary. It also enables non-null types for @semanticNonNull
fields, eliminating unnecessary null checks. Note that this pattern depends on
React error boundaries being configured in your application — proceed with
caution if error boundaries are not set up robustly.
For fields where you want to handle errors locally instead of throwing, use
@catch to receive errors inline as { ok: true, value: T } | { ok: false, errors: [...] }.
@required is also available for declaring that specific fields must be
non-null, but @throwOnFieldError + @catch is the preferred pattern for new
code.
See <llm-docs>/guides/throw-on-field-error-directive.mdx, <llm-docs>/guides/catch-directive.mdx,
and <llm-docs>/guides/semantic-nullability.mdx.
Always use @argumentDefinitions (for cursor/count variables),
@refetchable (to auto-generate the pagination query), and @connection (to
identify the connection for store management) together. Never write manual
pagination queries. See <llm-docs>/guided-tour/list-data/pagination.mdx.
When multiple components need to read client-side data, use Relay Resolvers to
define client-only fields on the GraphQL schema rather than prop-drilling or
React context. This gives client state the same composability and caching
guarantees as server data. Use useClientQuery for queries that read only
resolver-defined fields.
See <llm-docs>/guides/relay-resolvers/introduction.mdx for how to define resolvers.
This is the single most important rule. Do not read data from useFragment and
copy it into useState, and do not update that state manually in mutation
onCompleted callbacks.
// WRONG: Copying Relay data into React state
function UserProfile({userKey}) {
const data = useFragment(UserProfileFragment, userKey);
const [name, setName] = useState(data.name); // broken
const [commit] = useMutation(UpdateNameMutation);
const handleSave = (newName) => {
commit({
variables: {name: newName},
onCompleted: (response) => {
setName(response.updateName.user.name); // broken
},
});
};
return <span>{name}</span>;
}Why this is wrong: Relay's normalized store is the single source of truth. When
a mutation returns updated data with a matching id, Relay automatically
updates every component reading that data via useFragment. By copying into
useState, you create a second source of truth that Relay cannot update. The
component will show stale data whenever the record is updated by another
mutation, subscription, or refetch elsewhere in the app.
// CORRECT: Read directly from the fragment
function UserProfile({userKey}) {
const data = useFragment(UserProfileFragment, userKey);
const [commit, isInFlight] = useMutation(UpdateNameMutation);
const handleSave = (newName) => {
commit({variables: {name: newName}});
// No onCompleted needed — Relay updates the store automatically,
// and useFragment re-renders this component with the new data.
};
return <span>{data.name}</span>;
}Similarly, do not store a fragment key (the $key prop) in React state. Relay
garbage collects data that is no longer retained by a mounted query component —
if the component that originally fetched the data unmounts, a stashed key may
point to data that is no longer in the store.
Do not fetch all data in a parent's query and pass raw data objects as props to
children. This defeats data masking and creates tight coupling — adding a field
to a child component requires editing the parent's query. Note that the
relay/unused-fields lint rule will flag fields selected in the parent that
are only used by children — this is a good signal that you need to extract a
fragment.
// WRONG: Parent fetches everything, passes raw data
function Parent({queryRef}) {
const data = usePreloadedQuery(graphql`
query ParentQuery {
user {
name
email
avatarUrl
}
}
`, queryRef);
return <UserCard name={data.user.name} avatarUrl={data.user.avatarUrl} />;
}
// CORRECT: Child declares its own fragment
function Parent({queryRef}) {
const data = usePreloadedQuery(graphql`
query ParentQuery {
user {
...UserCard_user
}
}
`, queryRef);
return <UserCard user={data.user} />;
}Do not select fields individually in both a fragment and a mutation response — they will drift out of sync. Spread the fragment instead:
# WRONG
mutation UpdateUserMutation($input: UpdateUserInput!) {
updateUser(input: $input) {
user { id, name, email, avatarUrl }
}
}
# CORRECT
mutation UpdateUserMutation($input: UpdateUserInput!) {
updateUser(input: $input) {
user { ...UserCard_user }
}
}optimisticUpdater for store-dependent valuesIf an optimistic value depends on current store state (e.g., incrementing a
like count), use optimisticUpdater instead of optimisticResponse. Multiple
overlapping optimistic responses can compound incorrectly — two simultaneous
"like" mutations both read count=5 and set count=6, instead of 5→6→7. When one
rolls back, the store is left in an inconsistent state.
When a mutation has side effects too broad to capture in a single response
payload, use invalidateRecord() for targeted invalidation or
invalidateStore() for global invalidation. Pair with
useSubscribeToInvalidationState on mounted components to trigger refetches
for stale data automatically.
Relay treats cached data as fresh indefinitely by default. Two approaches:
queryCacheExpirationTime on the Relay Store to
automatically mark data stale after a duration.invalidateRecord() after mutations whose side effects
extend beyond the mutation response payload.Without explicit staleness handling, components can display arbitrarily old data after the user returns to a previously visited screen.
Without setting artifactDirectory in the compiler config, fragment references
may default to any, losing type safety. Set it and align your bundler's
module resolution accordingly. See <llm-docs>/getting-started/compiler-config.mdx.
@updatable for store manipulationPrefer typesafe updatable queries/fragments over raw store manipulation with
string-based field access (e.g., store.get(id).setValue(newName, 'name')).
Updatable fragments provide getters and setters, reducing the risk of typos
and type mismatches.
Do not call refetch() or fetchQuery() after mutations when spreading
component fragments in the mutation response would auto-update the store. Each
unnecessary refetch is a wasted network request and delays the UI update.
Reserve manual refetches for cases where the mutation's side effects are too
broad to capture in the response payload — and in those cases, prefer
invalidateRecord() (see above).
Prefer GraphQL Subscriptions over polling (setInterval + fetchQuery) or
manual refresh buttons for data that must stay current. Subscriptions push
updates only when data changes and integrate with Relay's normalized store
automatically.
Relay enforces that operation names match the module (file) they are defined in. Mismatched names cause compiler errors, not just style warnings.
| Element | Convention | Example |
|---|---|---|
| Fragment | ComponentName_propName | UserCard_user |
| Query | ComponentNameQuery | HomePageQuery |
| Mutation | ComponentNameMutation | LikeButtonMutation |
| Generated files | __generated__/*.graphql | Never edit these |
The module name is the filename stripped of all extensions (.react.js, .tsx,
etc.). UserCard.react.js → module name UserCard.
When moving a component to a new file, rename only the operations defined in that file to match the new filename. Do NOT rename fragment spreads that reference fragments owned by other modules — those names belong to their defining component.
Renaming an operation also changes its generated type name (e.g.,
UserCard_user$key → ProfileCard_user$key), so update all downstream imports
of those generated types.
__generated__/ filesThe next compiler run overwrites any manual edits. If you see type errors about missing generated types, run the compiler first — the types are just out of date, not missing.
Auto-formatters and linters can rename variables in ways that silently break
mutation calls. After running lint auto-fix, verify that variable keys in
commit({ variables: { ... } }) still match the generated Mutation$variables
type (check for data vs input mismatches in particular).
© hackers-pub, AGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .agents/skills/relay-best-practices of hackers-pub/hackerspub.
Open the folder on GitHubat commit 45b039b
Relay Best Practices next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Relay Best Practices this skillhackers-pub/hackerspub | 165 | — | ~4.6k | Automated safety check: Pass | AGPL-3.0 | |
| Shopify ExpertJeffallan/claude-skills | 12k | — | ~1.8k | Automated safety check: Pass | MIT | |
| Apollo Clientapollographql/skills | 117 | — | ~1.9k | Automated safety check: Pass | MIT | |
| Experience UI Bundle Deployforcedotcom/sf-skills | 1.1k | — | ~4.4k | Automated safety check: Notes | Apache-2.0 | |
| Shopifyericrisco/rsc-harness | 180 | — | ~3.2k | Automated safety check: Pass | MIT | |
| Apollo GraphqlKilo-Org/kilo-marketplace | 190 | 1 repos | ~3.1k | Automated safety check: Pass | Apache-2.0 |
Jeffallan/claude-skills
Builds Shopify themes in Liquid, custom apps, Storefront API storefronts and checkout extensions, using the Shopify CLI to lint, run locally and deploy.
apollographql/skills
Guide for building React applications with Apollo Client 4.x.
forcedotcom/sf-skills
MUST activate when the project has a uiBundles//src/ directory and the task involves deploying to an org or post-deploy org setup.
ericrisco/rsc-harness
A skill your agent uses when building or customizing a Shopify store across its three code surfaces — themes (Liquid, Online Store 2.0 sections, blocks and JSON templates), apps (Remix with the…
Kilo-Org/kilo-marketplace
Guidelines for developing GraphQL APIs and React applications using Apollo Client for state management, data fetching, and caching
reactive/data-client
Install and set up @data-client/react or @data-client/vue in a project.
hackers-pub/hackerspub
GraphQL schema design and review. An agent skill from hackers-pub/hackerspub.
hackers-pub/hackerspub
Fill in missing translations in web-next .po files, add i18n-aware UI labels to components, and ensure translation quality — consistent glossary terminology, correct punctuation/typography per…
hackers-pub/hackerspub
Performance best practices for Relay applications. An agent skill from hackers-pub/hackerspub.
hackers-pub/hackerspub
Make a commit in Git with an appropriate commit message for the currently staged changes.
Categories
Best practices for writing idiomatic Relay code. An agent skill from hackers-pub/hackerspub. Relay Best Practices is an agent skill from hackers-pub/hackerspub. Best practices for writing idiomatic Relay code.
Relay Best Practices fits situations like: modifying React components that use Relay for data fetching; you see useFragment; useLazyLoadQuery; usePreloadedQuery.
Run `npx skills add hackers-pub/hackerspub --skill relay-best-practices -a claude-code`. Or copy the skill folder (.agents/skills/relay-best-practices in hackers-pub/hackerspub) into .claude/skills/relay-best-practices in your project. Claude Code loads it when a task matches its description.
Run `npx skills add hackers-pub/hackerspub --skill relay-best-practices -a codex`. Or copy the skill folder (.agents/skills/relay-best-practices in hackers-pub/hackerspub) into .agents/skills/relay-best-practices in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add hackers-pub/hackerspub --skill relay-best-practices -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/relay-best-practices, .gemini/skills/relay-best-practices, .github/skills/relay-best-practices and .opencode/skills/relay-best-practices in your project.
Going by SKILL.md and its folder, Relay Best Practices needs the command-line tools its instructions call (npx and yarn). Our summary lists: Node.js.
SKILL.md names 1 domain. In commands or code: raw.githubusercontent.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Relay Best Practices is published under the AGPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 4.6k tokens (SKILL.md is roughly 18k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Relay Best Practices: Shopify Expert (Jeffallan/claude-skills, 12k stars), Apollo Client (apollographql/skills, 117 stars), Experience UI Bundle Deploy (forcedotcom/sf-skills, 1.1k stars) and Shopify (ericrisco/rsc-harness, 180 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
hackers-pub (a GitHub organization) maintains it in hackers-pub/hackerspub, which has 165 GitHub stars. The repository holds 5 skills in this directory. The repository was last updated on October 9, 2026.
Source: hackers-pub/hackerspub on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.