graphql-api-architect
Skill11 starsChanged 7 days agoApache-2.0View on GitHub
Designs the inbound GraphQL adapter of an already-modeled use case — schema-first, Spring for GraphQL on the servlet stack — into the `31-graphql.md` partial: the root fields and the input port each calls (the same port a REST adapter calls), types and nullability, mutation inputs and payloads with `userErrors`, Relay connections with a page ceiling, `@BatchMapping` child fields and the batch ports they ask for, the error map, field-level access, personal data per output field, and — on the project's first GraphQL case — the depth, complexity, timeout, batch-size, introspection, GraphiQL and CORS setup, plus a quota per caller or a concurrency cap when the use case states one. Use when the request involves GraphQL, a schema or `.graphqls` file, a query or mutation, a resolver, `@QueryMapping`, `@BatchMapping`, DataLoader, N+1 in GraphQL, a connection or cursor, GraphQL errors, or a rate limit on the GraphQL endpoint. Piece of the `/new-feature` pipeline: requires `10-domain.md` and a `00-use-case.md` whose `Trigger` names a GraphQL adapter in the given folder — and stops without them.
1 other project uses a version of this.
Adopted by
Most recently taken up by
- nerviz-ai/nervizword for word, first seen Oct 13, 2026
Other versions1 project uses a version of this.
Word for word · 1
- nerviz-ai/nerviz★ 11100% same
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository35 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- ai-architectSkill
- arch-adoptSkill
- arch-doctorSkill
- audit-usageSkill
- cache-architectSkill
- claude-code-architect-designerSkill
- docker-architectSkill
- domain-modelingSkill
- git-publishSkill
- gof-design-patternsSkill
- harness-lessonsSkill
- http-client-architectSkill
- init-projectSkill
- jobs-architectSkill
- messaging-architectSkill
- nerviz-diagramsSkill
- new-feature-implementSkill
- new-featureSkill
- new-projectSkill
- persistence-architectSkill
- platform-upgradeSkill
- project-bootstrapSkill
- project-configSkill
- report-issueSkill
- rest-api-architectSkill
- search-architectSkill
- security-architectSkill
- sonar-lessonsSkill
- sonarqube-setupSkill
- spikeSkill
- test-architectSkill
- transport-security-setupSkill
- triage-issueSkill
- use-case-designSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 1 is distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 169
Fix pagination — § 4: Every list that grows is a connection, forward only unless a client pages backwards.
- Very specific: line 172
Fix the batch loads — § 5: Every child field that costs I/O, the batch port it needs — keys in, map out — and what a missing key answers.
- Very specific: line 202
Personal data — § 8: Every output field walked through @.claude/rules/logging.md § Masking candidates.
- Very specific: line 221
Never a version from memory (@CLAUDE.md invariant 8).
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Available specs
!find "${CLAUDE_PROJECT_DIR:-.}/docs/use-cases" -mindepth 1 -maxdepth 1 -type d -name 'UC-*' 2>/dev/null | sort
Empty above → none yet, run /use-case-design first. (find, not an ls glob: under zsh an unmatched glob
aborts the command before any fallback runs.)
Target
$ARGUMENTS
GraphQL API Architect
Designs how a use case is exposed over GraphQL: which root fields exist and which input port
each calls, what the schema promises and what it may answer null, how a mutation reports what the
client can correct, how a list that grows is paged, which child fields load in batches and through
which port, what each failure becomes, which field needs its own access check, and — once per
project — the limits every operation runs under. What domain-modeling left as an input port, this
skill gives a GraphQL shape, next to or instead of the REST shape rest-api-architect gives it.
Entry rule: no GraphQL trigger, no GraphQL design. This skill reads
docs/use-cases/UC-NNN-<slug>/00-use-case.md and 10-domain.md and runs only when the Trigger
row names inbound GraphQL adapter or inbound REST and GraphQL adapters. Without 10-domain.md,
stop and say to run /domain-modeling; with a trigger that names no GraphQL adapter, stop and say
so — the protocol is the use case's choice, never this skill's.
Scope rule: queries and mutations over HTTP, nothing else. A case that needs a subscription, a
file upload, federation, a repository exposed as a resolver, generated types, or the reactive stack
is outside this skill (@.claude/rules/api-graphql.md, the scope paragraph, and
references/pitfalls.md § Out of scope). Stop, name which of them the case needs, and record it —
the user decides between narrowing the case with use-case-design and deferring it. An operation
callable without authentication is the same: the endpoint stays authenticated, and opening it is a
design decision outside this run.
Exit rule: it doesn't write code. It emits 31-graphql.md. The schema file, the controller, the
records, the resolver and the configuration come from the executor agent, which reads the partial
and the templates/ exemplars.
Rule rule: the rules don't live here. Protocol choice, boundary, schema, batching, pagination,
errors, access, demand limits, evolution, observability and tests are
@.claude/rules/api-graphql.md, which cites @.claude/rules/authorization.md,
@.claude/rules/error-handling.md and @.claude/rules/personal-data.md. This skill applies and
cites them; it doesn't reproduce them.
How it's invoked
Two paths: /graphql-api-architect by hand, or chained by /new-feature as step 3g, right after the
REST step and before security. That's why it does not carry disable-model-invocation — a skill
the model can't see is a skill the orchestrator can't call
(@.claude/decisions/0007-pipeline-skills-invocation.md). The guard against firing out of order is
the entry rule above.
Why this is a skill and not a subagent
Form 1, motivated by axis 1 of the designer's interview: a solution-design step that picks the
inbound protocol per case is planned, and without a GraphQL designer that choice had no path and fell
back to REST by omission; the maintainer chose to design it ahead of a run that shows the defect, on
the pitfalls the official documentation and the library's source record (references/pitfalls.md) —
seven of them reproduced only by running the exemplars. The closest rejected form was a GraphQL mode
of rest-api-architect: its interview reaches verbs, statuses and Idempotency-Key, not nullability,
batching, connections or demand limits, and its norm's territory cannot reach a GraphQL package. A
subagent fails the counter-test on all three points: the interview is the task, the reference fits
in references/ and templates/, and the partial is short.
Pinned to opus: the partial is what the executor implements verbatim, and the pin holding for the
rest of the turn keeps /new-feature on the model that designed it
(@.claude/decisions/0081-skill-model-required-per-class.md). Design record:
@.claude/decisions/0146-graphql-api-architect-skill.md (this repository only).
Boundary with neighboring skills
| Piece | Decides | Never decides |
use-case-design | The trigger — REST, GraphQL or both — and the Access row | The schema |
domain-modeling | The input ports, their read models, the exceptions and errorCodes | Anything about GraphQL |
rest-api-architect | The REST operations over the same ports, when the trigger names both | The GraphQL shape |
| this skill | Root fields and their ports, types and nullability, inputs, payloads and userErrors, connections, batch loads and the batch ports they ask for, the error map, personal data per output field, the project's GraphQL setup, GraphQL dependencies and configuration | The ports, the access rules, the batch query's statement, the tests' code |
security-architect | One access row per root field and per sensitive field, the meta-annotation each uses, the endpoint in the filter chain | Which fields exist |
persistence-architect | The batch port's statement and its index, the order's index | The batch port's existence (§ 5 asks for it) |
test-architect | Which test proves each case of § 10, and the schema snapshot test | — |
Doesn't collide with gof-design-patterns: that skill owns the catalog, this one decides which row
shapes the GraphQL layer of the case being designed (step 12b).
Procedure
Read the specs.
00-use-case.md(trigger,Access, Components table, response shape),10-domain.md(input ports and their signatures, read models, exception table witherrorCode), and — when present —30-rest.md(the REST operations over the same ports). Apply the entry rule and the scope rule. List the operations the case needs, each with the input port it calls.A port that returns an entity, or a read model a field would complete lazily, is a divergence, not something to work around here:
10-domain.mdisdomain-modeling's to change, and the operation stays undesigned until the port returns a complete read model.Survey — every answer the project already gave is inherited, never re-asked.
# Boot line and whether Spring for GraphQL is already in the build grep -m1 -A1 "<artifactId>spring-boot-starter-parent" pom.xml grep -nE "spring-boot-starter-graphql" pom.xml # GraphQL code and schema files already in the project grep -rlnE "@(QueryMapping|MutationMapping|SchemaMapping|BatchMapping)" --include='*.java' src/main 2>/dev/null find src/main/resources/graphql -name '*.graphqls' 2>/dev/null # Decisions earlier use cases recorded — the project setup lives in the first one's § 6 find docs/use-cases -name '31-graphql.md' 2>/dev/null # The project's admission setup — a REST case may have written it before any GraphQL case grep -rln "AdmissionProperties" --include='*.java' src/ 2>/dev/nullAnd the active blueprint's
packages.mapentry ending in.graphql— the package every controller, record and the wiring go to. No such entry → stop and say which line is missing from the blueprint, instead of choosing a package inside this use case.The templates' Boot-side packages (
GraphQlSourceBuilderCustomizer,@GraphQlTest) are Boot 4's. On a Boot 3 project the design is the same; record the line in the partial's header so the executor reads the Boot 3 names from the build, never from the template.Fact Inherited from Asked only when Project setup — limits, introspection, GraphiQL, CORS The first 31-graphql.md§ 6No earlier 31-graphql.md— first GraphQL case of the projectA type an earlier case declared ( Order,Money)The schema file and its 31-graphql.md§ 2Never — extended additively, never redefined Project-wide pieces ( GraphQlLimits,GraphQlConfig,GraphQlExceptionResolver)Already in the GraphQL package First GraphQL case Interview — only what steps 1 and 2 did not settle.
AskUserQuestion, at most 4 questions per call and never fewer than 2 real options per question; an axis with one sensible answer is decided and recorded, not asked (@CLAUDE.md§ Known pitfalls). Every option states its cost.Axis Decides Skip when Which fields and children the client reads — the screens or callers, and what each selects § 2, and which children are batch loads The response shape of 00-use-case.mdalready lists themDoes the list grow without bound § 4 — a connection, and its order Never a plain list for a growing set Each output field that matches a masking candidate — full, reduced or a reference, and who reads it § 8, and a field-level check No field matches Does an input update part of an object — may the client clear a field § 3 — ArgumentValueper fieldThe case creates or acts, never edits fields The project setup — internal or public clients, the origins a browser calls from, the slowest port § 6 Inherited - Fix the operations and the schema — § 1 and § 2. One root field per operation, each calling an
input port; a query never mutates, a mutation takes one
inputand returns one payload. Types, fields and nullability per@.claude/rules/api-graphql.md§ Schema, names per@.claude/rules/naming.md; a type an earlier case declared is extended, never redeclared. Form:templates/schema.graphqls.exampleandtemplates/GraphQlController.java.example. - Fix inputs and payloads — § 3. Shape validation on the input record; every
errorCodethe use case can raise that the client can correct goes touserErrors, with the input path it concerns. A partial update binds each optional field withArgumentValue. - Fix pagination — § 4. Every list that grows is a connection, forward only unless a client pages backwards; the order ends in a unique key; the default and maximum page come from § 6.
- Fix the batch loads — § 5. Every child field that costs I/O, the batch port it needs — keys
in, map out — and what a missing key answers. A batch port
10-domain.mddoes not declare is a requirement in § 9, never invented as if it existed. - Decide or inherit the project setup — § 6. First GraphQL case: every limit of
@.claude/rules/api-graphql.md§ Demand limits with its value and its reason — formtemplates/GraphQlConfig.java.exampleandtemplates/application-graphql.yml.example. Later cases:inherited from UC-NNN, and a change only with a reason and a row in## Impact on approved use cases.
8b. Admission — § 6's Admission rows. Only when 00-use-case.md's Admission row is not
none; no row, the rows read none. A limit is never proposed (@.claude/rules/inbound-admission.md
§ When a limit exists). The project's admission setup — where the quota is enforced, replicas, the
caller's key, the 503 wait — is asked exactly as @.claude/skills/rest-api-architect/SKILL.md
step 7c asks it, when step 2 found no AdmissionProperties; found, or written by a REST case's
30-rest.md § 8, it is inherited from UC-NNN. Then the case's limits:
| Limit | Where | Written |
| Quota | The whole GraphQL endpoint, per caller, before the document runs — never per field or per cost | The graphql entry of app.admission.quotas, stated and per-replica. The first case to state one sets it; a later case's different number is a CHANGE with a reason, since every operation shares it. The 429 is HTTP, Problem Details, before any GraphQL response — a row in § 7 and a case in § 10 |
| Cap | The root field's controller method, @Bulkhead(name = "inbound-<slug>") | Size below the scarcest resource the case holds, and why; the SERVICE_BUSY row in § 7 and its case in § 10 |
The pieces are @.claude/skills/rest-api-architect/templates/AdmissionConfig.java.example and
application-admission.yml.example, in the GraphQL package's admission subpackage when the
project has no REST adapter.
- Fix the error map — § 7. Each exception of
10-domain.mdthe operations can raise, where it lands (userErrorsor top-level), its classification anderrorCode, per@.claude/rules/api-graphql.md§ Errors. Form:templates/GraphQlExceptionResolver.java.example. - Personal data — § 8. Every output field walked through
@.claude/rules/logging.md§ Masking candidates; each match gets the recorded decision@.claude/rules/personal-data.md§ In transit requires. A field in clear for a narrower audience than the operation's needs a field-level check — a row forsecurity-architectin § 9. - Requirements to other partials — § 9. The batch ports to
10-domain.md; one statement per batch port and the order's index to20-persistence.md; one access row per root field and per sensitive field to32-security.md. Each a row, never an edit of another partial. Test cases, dependencies and configuration — § 10, § 11, § 12. § 10 lists every case
@.claude/rules/api-graphql.md§ Tests names, by level — slice, HTTP through the real chain, schema snapshot. § 11: the Initializr'sgraphqldependency and its test starter, version empty — managed by the Boot parent; read the id against the project's Boot when the build lacks it:curl -s "https://start.spring.io/dependencies?bootVersion=<boot from step 2>" \ -H 'Accept: application/vnd.initializr.v2.2+json' | grep -o '"graphql":{[^}]*}'Never a version from memory (
@CLAUDE.mdinvariant 8); no network → ask. The executor may writepom.xmlfor exactly these rows. § 12 lists every property, its value and its owner.
12b. Decide the design patterns of this layer. Run
@.claude/skills/gof-design-patterns/SKILL.md § Design-time use over the controllers, records
and mappers this case adds. The answer goes into ## Design patterns — none when nothing
matches, and absence is not none.
- Write the partial.
docs/use-cases/UC-NNN-<slug>/31-graphql.md, fromtemplates/graphql-spec.md.example. Thirteen numbered blocks plus## Design patterns, all mandatory, each written asnonewhen there is nothing — absence is notnone. - Report and stop. Path of the file written; each root field with its port; every connection with its ceiling; every batch load and the port it asks for; every field of § 8 in clear with its receiver; § 6 decided or inherited; each § 9 requirement. A port returning an entity, a growing list without a connection, or a child field with I/O and no batch is a finding. Don't invoke anyone else: the next pipeline step reads § 9.
What the partial contains
| Block | Fixes |
| 1 · Operations | One row per root field: kind, input port, return, REST counterpart |
| 2 · Schema | Types, fields, nullability and why, the read model behind each |
| 3 · Inputs and payloads | Input fields and shape validation, payload, userErrors codes |
| 4 · Pagination | Per connection: directions, order with its unique key, default and maximum page, the cursor's keys |
| 5 · Batch loads | Per child field: the batch port (a requirement when new), key, missing-key answer |
| 6 · Project setup | Every limit with its value and reason — or inherited from UC-NNN — and the Admission rows: none, or the setup and this case's quota and cap (step 8b) |
| 7 · Error map | Situation, where it lands, classification, errorCode |
| 8 · Personal data | Per matching output field: form, receiver and reason |
| 9 · Requirements to other partials | Batch ports, statements and indexes, access rows |
| 10 · Contract test cases | Every case, by level |
| 11 · Declared dependencies | The starter and its test starter |
| 12 · Configuration | Every property, its value, its owner |
| 13 · Deferred | Same shape as every partial. none when nothing was deferred |
| Design patterns | Each pattern the controllers, records or mappers adopt — step 12b |
Plus ## Impact on approved use cases and ## Implementation order, as in every partial.
The exemplars in templates/ are reference for form, not files to copy. Each was compiled and
run against the classpath the Initializr resolved on the day it was written:
The mapper comes in two exemplars — OrderGraphQlMapper inside GraphQlController.java.example, and GraphQlMapStructMapper.java.example beside it — because the mechanism is the project's, not this partial's: the partial says what maps to what, and the executor writes it in the mechanism the root CLAUDE.md's **Mappers: paragraph names (@.claude/rules/mapping.md).
| Exemplar | Shape of |
templates/schema.graphqls.example | The schema file: nullability, a connection by suffix, a mutation input and payload, UserError |
templates/GraphQlController.java.example | The input ports and read models it calls, the adapter records, the mapper, @QueryMapping, a connection through ScrollSubrange and Window, @MutationMapping with userErrors, two @BatchMapping, a guarded @SchemaMapping |
templates/GraphQlMapStructMapper.java.example | The same read model → schema type mapper as a MapStruct interface, for a project whose mechanism is MapStruct: generated records, a Money from two source fields through a @Named method |
templates/GraphQlConfig.java.example | GraphQlLimits, depth, complexity, timeout, batch size, the schema inspection that fails the startup |
templates/GraphQlExceptionResolver.java.example | Each family to a classification and errorCode; null for the rest |
templates/application-graphql.yml.example | Introspection and GraphiQL by profile, CORS, app.graphql.* |
templates/graphql-spec.md.example | The partial |
The test shapes are test-architect's: GraphQlControllerTest.java.example,
GraphQlHttpIT.java.example, GraphQlSchemaCompatibilityTest.java.example.
Contract
Class: design — the territory is skill_classes.design in
@.claude/schemas/extensions.json, and ArchHook.java guard enforces it. Writes inside the use
case folder and nothing else.
Reads docs/use-cases/UC-NNN-<slug>/00-use-case.md (mandatory), 10-domain.md
(mandatory), 30-rest.md (when present), the 31-graphql.md of earlier cases, pom.xml, the schema
files under src/main/resources/graphql/, the active blueprint's packages.map, the Initializr's
metadata, @.claude/rules/api-graphql.md, @.claude/rules/authorization.md,
@.claude/rules/error-handling.md, @.claude/rules/personal-data.md, @.claude/rules/logging.md,
@.claude/rules/naming.md, @.claude/rules/architecture-ddd.md, and this skill's references/ —
plus, with an Admission row, @.claude/rules/inbound-admission.md and the partial that wrote the
admission setup.
Writes docs/use-cases/UC-NNN-<slug>/31-graphql.md. Nothing else.
Owns the root fields and the port each calls, the schema's types and nullability, inputs,
payloads and userErrors, connections and their ceilings, batch loads and the batch ports they ask
for, the GraphQL error map, the personal-data decision per output field, the project's GraphQL setup,
the GraphQL endpoint's quota and each root field's cap, and GraphQL dependencies and configuration.
Does not decide the input ports, their read models or the exceptions (10-domain.md), the
trigger or the Access row (00-use-case.md), the REST operations (30-rest.md), the access
rule of each field and the filter chain (32-security.md), the batch statements and indexes
(20-persistence.md), or the tests (40-tests.md). Does not write Java, schema files, pom.xml
or application.yml — the executor does, from this partial. Doesn't touch .claude/rules/**.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

