docs / grandstack / Agents

Agent guide

For coding agents (Claude Code or any other) and the people directing them. It says what the system is, where to change what, how to verify, and what goes wrong. It is agent-agnostic; the worked example uses Claude Code.

Where to run this. Docker Compose commands run inside a clone of this repository (git clone https://github.com/grand-stack/grandstack, then cd grandstack), with the repositories it builds cloned beside it. The quickstart has the exact steps.

Mental model in six lines

  1. Neo4j holds a graph. The GraphQL API is generated from grandstack-server/schema/schema.graphql; there are no resolvers to edit.
  2. The web app (grandstack-web) asks that API for data using operations written with graphql() and typed by npm run codegen against the live schema.
  3. State a user may want to share (filters) lives in the URL.
  4. Sample data comes from a versioned Cypher seed; titles and names are unique keys.
  5. Writes go through generated mutations; a server plugin keeps stored film counts correct.
  6. The default stack has no authentication, and the app can edit and delete everything. An opt-in setup (compose.auth.yaml, the grandstack-auth repo) adds login, a gateway and row-level rules; grandstack-web is intentionally not part of it.

Notes on setup

npm ci prints npm warn install-scripts ... approve warnings; they are harmless. The package versions in package.json match the git tags.

Where to change what

You want to…ChangeThen run
Add or change a field, type or relationshipgrandstack-server/schema/schema.graphql (+ seed if it needs data)server checks, then npm run codegen in the web repo
Change the sample datagrandstack-server/seed/movies.cypher, bump // seed-versionrestart the server
Add a computed field@cypher in the schemaserver checks
Change server behaviour or add a settinggrandstack-server/src/server checks
Show a field, add a filter, page or formgrandstack-web/src/web checks
Change look and feelgrandstack-web/src/theme/tokens.css, src/styles.cssweb checks
Change ports, services or settings of the stackgrandstack/compose.yamldocker compose up --build
Change who can do what (roles, permissions, rules)grandstack-auth (gateway/rules.ts, schema/auth.graphql, keycloak/grandstack-realm.json)its smoke script and tests
Add login to a front endfollow grandstack-auth/docs/exercise-add-auth-to-grandstack-web.md in your own copyits acceptance check
Use your own datasetsee build your own app

Each repository has recipes for the common changes: docs/recipes.md in grandstack-server and in grandstack-web. Start there.

Start the stack

cd grandstack
cp .env.example .env      # once
docker compose up --build # web :3000, GraphQL :4000/graphql, Neo4j browser :7474

# with login (development only): gateway :4000, Keycloak :8081, auth demo client :3001
docker compose -f compose.yaml -f compose.auth.yaml up --build

# with federation (Wikipedia summaries on films and people; needs internet): gateway :4000, subgraphs :4001 and :4010
docker compose -f compose.yaml -f compose.federation.yaml up --build

# with an MCP server for agents: http://localhost:4100/mcp (read-only; AGENTS_ALLOW_MUTATIONS=true to write)
docker compose -f compose.yaml -f compose.agents.yaml up --build

Wait for the server log line GraphQL ready at http://localhost:4000/graphql. Use docker compose down -v to reset the data to the sample.

Verification checklist

Run what matches the repo you changed. All of it must pass before you call a change done.

# grandstack-server
npm run lint && npm test && npm run schema:check && npm run docs:check

# grandstack-web (codegen needs a server running with the schema you want; it reads
# GRAPHQL_URL, default http://localhost:4000/graphql)
npm run codegen && npm run typecheck && npm test && npm run docs:check

# grandstack-web browser checks (freshly seeded stack; creates and deletes ZZ-prefixed test data)
npm run e2e

# grandstack-auth: unit tests, then (with the auth stack running) the token-level and browser checks
(cd gateway && npm ci && npm test && npm run typecheck)
(cd client && npm ci && npm test && npm run typecheck)
npm ci && npm run docs:check && npm run smoke && npm run e2e

# grandstack-agents: tests and types need no stack; live needs the open stack, auth:check the auth stack
npm ci && npm test && npm run typecheck && npm run docs:check && npm run live

# grandstack-federation: tests and types need no stack; smoke needs the federation stack and internet
npm ci && npm test && npm run typecheck && npm run docs:check && npm run smoke

schema:check needs a git checkout with the schema committed at HEAD (commit the baseline before you edit). docs:check fails until you have run npm run docs:schema after a schema change; commit the regenerated reference.

For a server schema change also check the live API, for example:

curl -s localhost:4000/graphql -H 'content-type: application/json' \
  -d '{"query":"{ movies(limit:1) { title rating } }"}'

Do not claim a UI change works from a build alone: open the page (or use npm run e2e screenshots with OUT=dir) and look.

Using the API without writing code

The endpoint accepts introspection, so an agent can discover the schema itself:

curl -s localhost:4000/graphql -H 'content-type: application/json' \
  -d '{"query":"{ __schema { queryType { fields { name description } } mutationType { fields { name } } } }"}'

Every type and field defined in the schema has a description (lint enforces it), and grandstack-server/docs/schema-reference.md lists them. The generated queries and mutations (movies, createMovies, …) have no descriptions but follow a fixed naming pattern per type (see that repo’s docs/schema-guide.md). Filters look like movies(where: { rating: { gte: 8 }, genres: { some: { name: { in: ["Drama"] } } } }); writes are covered in grandstack-server/docs/mutations.md. An MCP server that runs GraphQL statements is available with compose.agents.yaml (port 4100, read-only by default); see grandstack-agents (README.md, docs/direct-graphql.md). How well an agent does depends on how the type definitions are written; see grandstack-agents docs/schema-design-for-agents.md.

Gotchas that cost time

  • Every type, field and argument needs a description in the schema, or lint fails.
  • Types need @node (v7). New Neo4j directives need a stub in grandstack-server/tooling/neo4j-directives.graphql.
  • Scalar updates are { set: value }. A bare value fails validation.
  • Relationship updates must be diffs. “Disconnect all, then connect” in one mutation removes the new links, because the disconnect runs last. buildUpdateInput in the web repo shows the right shape.
  • contains is case-sensitive. The web app matches several casings.
  • Seed changes need a bumped // seed-version. Cypher map keys are bare words.
  • Operation names must be unique across the web app, and variables used in non-null positions must be declared non-null.
  • Keep graphql on 16.x in both repos. Pin exact dependency versions.
  • Do not add @neo4j-ndl/* to the web app: it is GPL-3.0 and the repo is Apache-2.0.
  • VITE_GRAPHQL_URL is fixed at build time and must be reachable from the browser; the server’s CORS_ORIGIN must allow the web origin.
  • Text inputs that write to the URL need local state and a debounce, or fast typing drops characters.
  • Never expose the stack publicly. The default stack has no auth, and the auth setup is development-only (demo realm, known passwords, plain HTTP).
  • Auth: a new mutation must be added to MUTATION_PERMISSIONS in grandstack-auth/gateway/rules.ts or the gateway refuses it; server rules must be filter (not validate) and avoid DateTime (both need APOC); AUTH_ISSUER is the browser-facing URL while AUTH_JWKS_URL is the container-reachable one; realm edits need a recreated Keycloak. More in grandstack-auth/AGENTS.md.
  • Commit generated files when they change: grandstack-web/src/graphql/generated/ and grandstack-server/docs/schema-reference.md.

Keep the docs true

Docs live next to the code they describe. When you change behaviour, update the doc in the same change: environment variables in docs/configuration.md (server), routes and folder map in docs/architecture.md (web), versions in versioning and releases. npm run docs:check fails on a stale schema reference (server) or a broken relative link (all repos).

Example: asking Claude Code to make a change

Open Claude Code in the folder that holds the repositories, then give it a task and point it at the docs:

Add a country field to Movie and show it on the movie page. Follow grandstack/docs/agents.md and the recipes in each repo’s docs/recipes.md. Run the checks before you say it is done.

A good run follows the recipes: add the described field to the schema, lint and check for breaking changes, regenerate the schema reference, restart the server, add country to the movie query in the web app, run npm run codegen, render it in MovieDetail.tsx, then run the checks above and look at the page. Any other agent can follow the same documents.

Source: grandstack/docs/agents.md (this page is a copy; edit it in the repository)