用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/diegosouzapw/awesome-omni-skill --skill gqlguide命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | gql:guide |
| description | Interactive guide to soda-gql features and patterns |
| user-invocable | true |
| argument-hint | ["topic or question"] |
| allowed-tools | Read, Grep, Glob, AskUserQuestion |
This skill provides interactive guidance on soda-gql features, syntax patterns, and best practices. Use $ARGUMENTS to route to specific topics, or ask the user to choose a topic.
Parse $ARGUMENTS to determine the user's intent, or use AskUserQuestion to offer topic selection.
If $ARGUMENTS is empty or unclear, use AskUserQuestion:
Question: "What would you like guidance on?" Options:
For each topic, provide:
soda-gql supports tagged template syntax for writing GraphQL fragments and operations. Only gql is exported from the generated runtime:
import { gql } from "<outdir-path>"; // e.g. "@/graphql-system"
// Fragment with tagged template
const userFragment = gql.default(({ fragment }) =>
fragment("UserFields", "User")`{
id
name
email
}`(),
);
// Operation with tagged template
const getUserQuery = gql.default(({ query }) =>
query("GetUser")`($id: ID!) {
user(id: $id) {
id
name
}
}`(),
);
Decision Tree:
Fragment definition:
Fragment spreading (Fragment → Fragment):
...${otherFragment}Operation definition:
.spread(), no aliases, no $colocate.spread(), aliases, or $colocateSpecial features:
.spread() → callback builder onlyBoth tagged templates reject interpolation with values:
fragment("Name", "Type")\${value}`` → ❌ Throws errorquery("Name")\{ field(id: ${id}) }`` → ❌ Throws errorThe only valid interpolation is fragment-to-fragment spreading: fragment("Name", "Type")\...${otherFragment} ...``.
Operations with fragment spreads MUST use callback builder syntax with .spread() instead of tagged template interpolation.
playgrounds/vite-react/src/graphql/callback-builder-features.tsplaygrounds/vite-react/src/graphql/fragment-spread-patterns.mdTagged template fragment:
// playgrounds/vite-react/src/graphql/fragments.ts
const userFields = gql.default(({ fragment }) =>
fragment("UserFields", "User")`{
id
name
email
createdAt
}`(),
);
Tagged template operation (no spreads):
// playgrounds/vite-react/src/graphql/operations.ts
const simpleQuery = gql.default(({ query }) =>
query("GetUsers")`{
users {
id
name
}
}`(),
);
Callback builder operation (with spreads):
// playgrounds/vite-react/src/graphql/callback-builder-features.ts
const userQuery = gql.default(({ query, $var }) =>
query.operation({
name: "GetUser",
variables: {
...$var("id").ID("!"),
},
fields: ({ f, $ }) => ({
...f.user({ id: $.id })(({ f }) => ({
...userFields.spread(),
})),
}),
}),
);
✅ Simple fragment with tagged template:
const fields = gql.default(({ fragment }) =>
fragment("UserBasic", "User")`{
id
name
email
}`(),
);
✅ Fragment spreading another fragment (tagged template):
const extendedFields = gql.default(({ fragment }) =>
fragment("ExtendedUser", "User")`{
...${userFields}
createdAt
updatedAt
}`(),
);
❌ Operation with fragment spread (WRONG - tagged template):
// This will FAIL - cannot use tagged template interpolation for fragment spreads in operations
const badQuery = gql.default(({ query }) =>
query("BadQuery")`{
user {
${userFields}
}
}`(),
);
✅ Operation with fragment spread (CORRECT - callback builder):
const userQuery = gql.default(({ query, $var }) =>
query.operation({
name: "GetUser",
variables: { ...$var("id").ID("!") },
fields: ({ f, $ }) => ({
...f.user({ id: $.id })(({ f }) => ({
...userFields.spread(),
})),
}),
}),
);
Fragments define reusable field selections with type safety. They can be spread into operations or composed into other fragments.
"Fragments declare requirements; operations declare contract"
playgrounds/vite-react/src/graphql/fragment-spread-patterns.mdplaygrounds/vite-react/src/graphql/nested-fragment-verification.tsSimple fragment:
const userBasic = gql.default(({ fragment }) =>
fragment("UserBasic", "User")`{
id
name
email
}`(),
);
Fragment with variables:
const userConditional = gql.default(({ fragment }) =>
fragment("ConditionalUser", "User")`($includeEmail: Boolean!) {
id
name
email @include(if: $includeEmail)
}`(),
);
Fragment spreading (Fragment → Fragment):
const userExtended = gql.default(({ fragment }) =>
fragment("ExtendedUser", "User")`{
...${userBasic}
createdAt
updatedAt
}`(),
);
Operation spreading fragment (callback builder):
const getUserQuery = gql.default(({ query, $var }) =>
query.operation({
name: "GetUser",
variables: {
...$var("id").ID("!"),
...$var("includeEmail").Boolean("!"),
},
fields: ({ f, $ }) => ({
...f.user({ id: $.id })(({ f }) => ({
...userConditional.spread({ includeEmail: $.includeEmail }),
})),
}),
}),
);
✅ Fragment composition via tagged template:
const baseFields = gql.default(({ fragment }) =>
fragment("UserBase", "User")`{ id name }`(),
);
const extendedFields = gql.default(({ fragment }) =>
fragment("UserExtended", "User")`{
...${baseFields}
email
}`(),
);
✅ Operation declares all variables:
const getUserQuery = gql.default(({ query, $var }) =>
query.operation({
name: "GetUser",
variables: {
...$var("id").ID("!"),
...$var("includeEmail").Boolean("!"), // ALL variables, including fragment requirements
},
fields: ({ f, $ }) => ({
...f.user({ id: $.id })(({ f }) => ({
...userConditional.spread({ includeEmail: $.includeEmail }),
})),
}),
}),
);
❌ Auto-merge expectation (WRONG):
// Fragment declares $includeEmail
const frag = gql.default(({ fragment }) =>
fragment("F", "User")`($includeEmail: Boolean!) {
id name email @include(if: $includeEmail)
}`(),
);
// Operation does NOT auto-inherit variables — must declare includeEmail explicitly
const badQuery = gql.default(({ query, $var }) =>
query.operation({
name: "GetUser",
variables: { ...$var("id").ID("!") }, // Missing includeEmail!
fields: ({ f, $ }) => ({
...f.user({ id: $.id })(({ f }) => ({
...frag.spread(), // Will fail — $includeEmail not in scope
})),
}),
}),
);
Operations define the GraphQL query/mutation/subscription structure with variables, arguments, and field selections.
Operations declare the contract:
$var("name").Type("!") to declare variablesplaygrounds/vite-react/src/graphql/operations.tsplaygrounds/vite-react/src/graphql/callback-builder-features.tsSimple query (tagged template):
const getUsers = gql.default(({ query }) =>
query("GetUsers")`{
users {
id
name
}
}`(),
);
Query with variables (tagged template):
const getUser = gql.default(({ query }) =>
query("GetUser")`($id: ID!) {
user(id: $id) {
id
name
email
}
}`(),
);
Query with fragment spread (callback builder):
const getUserWithFragment = gql.default(({ query, $var }) =>
query.operation({
name: "GetUserWithFragment",
variables: {
...$var("id").ID("!"),
},
fields: ({ f, $ }) => ({
...f.user({ id: $.id })(({ f }) => ({
...userFields.spread(),
})),
}),
}),
);
Mutation (tagged template):
const createUser = gql.default(({ mutation }) =>
mutation("CreateUser")`($input: CreateUserInput!) {
createUser(input: $input) {
id
name
}
}`(),
);
✅ Simple query (tagged template):
const getUserQuery = gql.default(({ query }) =>
query("GetUser")`($id: ID!) {
user(id: $id) {
id
name
posts {
id
title
}
}
}`(),
);
✅ Operation with multiple variables (callback builder):
const getUserPosts = gql.default(({ query, $var }) =>
query.operation({
name: "GetUserPosts",
variables: {
...$var("id").ID("!"),
...$var("limit").Int(),
...$var("offset").Int(),
},
fields: ({ f, $ }) => ({
...f.user({ id: $.id })(({ f }) => ({
...f.posts({ limit: $.limit, offset: $.offset })(({ f }) => ({
id: f.id,
title: f.title,
})),
})),
}),
}),
);
Union types in GraphQL represent a value that could be one of several types. soda-gql handles union types using standard GraphQL inline fragment syntax in tagged templates.
Union handling uses standard GraphQL inline fragment syntax (... on TypeName { fields }). Always include __typename for type discrimination:
const searchQuery = gql.default(({ query }) =>
query("Search")`($term: String!) {
search(term: $term) {
__typename
... on User {
id
name
}
... on Organization {
id
name
members
}
}
}`(),
);
playgrounds/vite-react/src/graphql/union-type-verification.tsplaygrounds/vite-react/src/graphql/callback-builder-features.tsUnion field selection (tagged template):
const searchQuery = gql.default(({ query }) =>
query("Search")`($term: String!) {
search(term: $term) {
__typename
... on User {
id
name
email
}
... on Post {
id
title
content
}
}
}`(),
);
Union with fragment spread (callback builder):
const userFields = gql.default(({ fragment }) =>
fragment("UserFields", "User")`{ id name email }`(),
);
const postFields = gql.default(({ fragment }) =>
fragment("PostFields", "Post")`{ id title content }`(),
);
const searchQuery = gql.default(({ query, $var }) =>
query.operation({
name: "Search",
variables: { ...$var("term").String("!") },
fields: ({ f, $ }) => ({
...f.search({ term: $.term })(({ f }) => ({
__typename: f.__typename,
...userFields.spread(),
...postFields.spread(),
})),
}),
}),
);
✅ Always include __typename:
const q = gql.default(({ query }) =>
query("Search")`($term: String!) {
search(term: $term) {
__typename
... on TypeA { id fieldA }
... on TypeB { id fieldB }
}
}`(),
);
✅ Exhaustive member handling:
const q = gql.default(({ query }) =>
query("SearchAll")`($term: String!) {
search(term: $term) {
__typename
... on User { id name }
... on Organization { id name }
... on Bot { id label }
}
}`(),
);
GraphQL directives modify field behavior (@include, @skip) or provide metadata for tools. soda-gql supports standard and custom directives.
@include(if: Boolean), @skip(if: Boolean)Tagged template with static values:
gql.default(({ fragment }) =>
fragment("UserFields", "User")`{
id
name
email @include(if: true)
}`(),
);
Tagged template with variables:
gql.default(({ fragment }) =>
fragment("ConditionalUser", "User")`($includeEmail: Boolean!) {
id
name
email @include(if: $includeEmail)
}`(),
);
playgrounds/vite-react/src/graphql/directive-verification.ts@include directive:
const conditionalFields = gql.default(({ fragment }) =>
fragment("ConditionalUser", "User")`($showEmail: Boolean!) {
id
name
email @include(if: $showEmail)
}`(),
);
@skip directive:
const fields = gql.default(({ fragment }) =>
fragment("SkipEmail", "User")`($hideEmail: Boolean!) {
id
name
email @skip(if: $hideEmail)
}`(),
);
Custom directive:
// Assuming schema has: directive @sensitive on FIELD_DEFINITION
const userFields = gql.default(({ fragment }) =>
fragment("SensitiveUser", "User")`{
id
name
socialSecurityNumber @sensitive
}`(),
);
✅ Conditional field inclusion (callback builder with fragment spread):
const detailsFragment = gql.default(({ fragment }) =>
fragment("UserDetails", "User")`($includeDetails: Boolean!) {
bio @include(if: $includeDetails)
website @include(if: $includeDetails)
}`(),
);
const getUserQuery = gql.default(({ query, $var }) =>
query.operation({
name: "GetUser",
variables: {
...$var("id").ID("!"),
...$var("includeDetails").Boolean("!"),
},
fields: ({ f, $ }) => ({
...f.user({ id: $.id })(({ f }) => ({
id: f.id,
name: f.name,
...detailsFragment.spread({ includeDetails: $.includeDetails }),
})),
}),
}),
);
soda-gql allows attaching metadata to fragments and operations for build-time processing (e.g., component mapping, documentation generation). Metadata is passed as an argument to the template call.
Static metadata — passed as argument to the template call:
const frag = gql.default(({ fragment }) =>
fragment("UserFields", "User")`{
id
name
}`({
metadata: { component: "UserCard" },
}),
);
Callback metadata — receives variables for dynamic values:
const frag = gql.default(({ fragment }) =>
fragment("UserFields", "User")`($userId: ID!) {
id
name
}`({
metadata: ({ $ }: { $: { userId: string } }) => ({
cacheKey: `user:${$.userId}`,
}),
}),
);
playgrounds/vite-react/src/graphql/callback-builder-features.tsplaygrounds/vite-react/src/graphql/metadata-verification.tsStatic fragment metadata:
const userFragment = gql.default(({ fragment }) =>
fragment("UserCard", "User")`{
id
name
email
}`({
metadata: { component: "UserCard", description: "User profile data" },
}),
);
Callback metadata with variables:
const userFragment = gql.default(({ fragment }) =>
fragment("CachedUser", "User")`($userId: ID!) {
id
name
email
}`({
metadata: ({ $ }: { $: { userId: string } }) => ({
cacheKey: `user:${$.userId}`,
}),
}),
);
Callback builder operation with metadata:
const q = gql.default(({ query, $var }) =>
query.operation({
name: "GetUser",
variables: { ...$var("id").ID("!") },
metadata: ({ $, fragmentMetadata }) => ({
entityId: $.id,
fragmentCount: fragmentMetadata?.length ?? 0,
}),
fields: ({ f, $ }) => ({
...f.user({ id: $.id })(({ f }) => ({
...userFragment.spread(),
})),
}),
}),
);
✅ Component mapping:
gql.default(({ fragment }) =>
fragment("UserProfile", "User")`{ id name }`({
metadata: { component: "UserProfile" },
}),
);
✅ Dynamic cache key:
gql.default(({ fragment }) =>
fragment("CachedUser", "User")`($id: ID!) { id name }`({
metadata: ({ $ }: { $: { id: string } }) => ({
cacheKey: `user:${$.id}`,
}),
}),
);
Setting up a new soda-gql project involves config file creation, schema setup, and initial codegen.
Install dependencies:
bun add @soda-gql/core @soda-gql/builder
bun add -d @soda-gql/cli
Add framework plugin (optional but recommended):
# For Vite
bun add -d @soda-gql/vite-plugin
# For Next.js
bun add -d @soda-gql/next-plugin
Create config file (soda-gql.config.ts):
import { defineConfig } from '@soda-gql/config';
export default defineConfig({
outdir: './src/graphql/generated',
schemas: {
default: {
schemaFiles: ['./schema.graphql'],
},
},
});
Run initial codegen:
bun run soda-gql codegen schema
Configure build plugin (Vite example):
// vite.config.ts
import { sodaGql } from '@soda-gql/vite-plugin';
export default {
plugins: [sodaGql()],
};
README.md — Installation and quick startplaygrounds/vite-react/src/graphql/ — Working examples of all featuresIssue: codegen fails with "config not found"
soda-gql.config.{ts,js,mjs}export defaultIssue: "Cannot find module '@soda-gql/core'"
bun install to install dependenciesIssue: Types not updating in editor
soda-gql provides LSP (Language Server Protocol) integration for real-time diagnostics, autocomplete, and hover information in editors.
VS Code:
{
"soda-gql.configPath": "./soda-gql.config.ts"
}
Other editors:
The LSP validates:
Issue: LSP not providing diagnostics
found: true in project detection)Issue: False positive errors
bun run soda-gql codegen schema to sync generated typessoda-gql codegen generates TypeScript types from GraphQL schemas (schema codegen) and validates/generates types from tagged templates (typegen).
Schema codegen:
bun run soda-gql codegen schema
Type generation (typegen):
bun run soda-gql typegen
Development workflow:
bun run soda-gql codegen schemaWatch mode (if supported):
bun run soda-gql codegen schema --watch
docs/guides/monorepo-infrastructure.md — Build systemIssue: "Schema file not found"
Issue: Typegen shows "unknown field"
bun run soda-gql codegen schemaIssue: Generated types not updating
Fragment colocation places fragment definitions near the components that use them, improving code organization and enabling build-time optimizations.
$colocate in callback builder spread:
const userQuery = gql.default(({ query, $var }) =>
query.operation({
name: "GetUser",
variables: { ...$var("id").ID("!") },
fields: ({ f, $ }) => ({
...f.user({ id: $.id })(({ f }) => ({
id: f.id,
...userFragment.spread({ $colocate: true }),
})),
}),
}),
);
Component colocation:
// UserCard.tsx
export const userCardFragment = gql.default(({ fragment }) =>
fragment("UserCardFields", "User")`{
id
name
email
avatarUrl
}`(),
);
export function UserCard({ user }) {
// Component uses fragment data
}
Colocation enables:
playgrounds/vite-react/src/graphql/callback-builder-features.ts — $colocate examples✅ Component-fragment pair:
// UserProfile.tsx
const userProfileFragment = gql.default(({ fragment }) =>
fragment("UserProfile", "User")`{
id
name
email
bio
}`(),
);
function UserProfile({ data }) {
// Use fragment data
}
✅ Fragment composition with colocation:
const parentQuery = gql.default(({ query, $var }) =>
query.operation({
name: "GetUserPage",
variables: { ...$var("id").ID("!") },
fields: ({ f, $ }) => ({
...f.user({ id: $.id })(({ f }) => ({
...profileFragment.spread({ $colocate: true }),
...settingsFragment.spread({ $colocate: true }),
})),
}),
}),
);
If the user's question doesn't match a specific topic, use Grep to search documentation:
Before completing this skill, ensure:
Token-efficient tracking for AI orchestration. CLI-first for status updates (~50 tokens), agent fallback for complex ops (~1KB). Use when: updating task status, querying blockers, creating progress files, validating phases.
AshAi extension guidelines for integrating AI capabilities with Ash Framework. Use when implementing vectorization/embeddings, exposing Ash actions as LLM tools, creating prompt-backed actions, or setting up MCP servers. Covers semantic search, LangChain integration, and structured outputs.
This skill should be used when solving hard questions, complex architectural problems, or debugging issues that benefit from GPT-5 Pro or GPT-5.1 thinking models with large file context. Use when standard Claude analysis needs deeper reasoning or extended context windows.
基于 SOC 职业分类