Skip to main content

GraphQL API

These docs are powered by GraphQL. Every page you are reading also lives behind a live, typed GraphQL endpoint that ships with this repo. The documentation is the data: each Markdown file under docs/ is a Doc you can fetch, filter, and full-text search through a single endpoint.

That makes the docs programmable. Instead of scraping HTML or guessing at URLs, an AI agent can introspect the schema once and then read exactly the pages, sections, and search hits it needs — as JSON, in the shape it asked for. A self-describing single-endpoint API turns "find the right doc" into one query. The same endpoint is just as handy for developers building integrations, link checkers, or search over the docs.

The endpoint

Every read goes to the same place:

POST http://localhost:4000/graphql
  • POST with Content-Type: application/json.
  • Read-only and open. No API key, no Authorization header, no login. These are public docs, so the API is public too.
  • No mutations. The schema exposes queries only — there is nothing to write.
  • Introspection is on and GraphiQL is on. Open http://localhost:4000/graphql in a browser for an interactive explorer, or let an agent introspect the schema at runtime.

Start it locally from the repo root:

npm run graphql
# -> Keen Docs GraphQL API — 49 docs loaded
# GraphiQL: http://localhost:4000/graphql
# Endpoint: POST http://localhost:4000/graphql

The port is configurable with $PORT (default 4000). See Running the API for the full setup.

30 seconds: your first query

Ask the API to describe itself. The meta query needs no arguments and no credentials:

curl -sS http://localhost:4000/graphql -H 'content-type: application/json' \
--data '{"query":"query { meta { name docCount sections endpoint } }"}'
{
"data": {
"meta": {
"name": "Keen Docs GraphQL API",
"docCount": 49,
"sections": ["chat", "graphql", "keen-extension", "onboarding", "organization", "root", "tooling"],
"endpoint": "/graphql"
}
}
}

Now search the docs. search runs a free-text match across each page's title, description, and body:

curl -sS http://localhost:4000/graphql -H 'content-type: application/json' \
--data '{"query":"query { search(query: \"introspection\", limit: 5) { id title slug section } }"}'
{
"data": {
"search": [
{ "id": "graphql/agents", "title": "Drive the docs from an agent", "slug": "/docs/graphql/agents", "section": "graphql" },
{ "id": "graphql/errors-and-limits", "title": "Errors and limits", "slug": "/docs/graphql/errors-and-limits", "section": "graphql" },
{ "id": "graphql/index", "title": "GraphQL API", "slug": "/docs/graphql", "section": "graphql" },
{ "id": "graphql/queries", "title": "Queries", "slug": "/docs/graphql/queries", "section": "graphql" },
{ "id": "graphql/running-the-api", "title": "Running the API", "slug": "/docs/graphql/running-the-api", "section": "graphql" }
]
}
}

You select the fields; the response mirrors exactly what you asked for. That predictability is what makes the API easy for an agent to drive.

What you can query

Five root fields cover the whole surface:

FieldReturnsUse it to
metaApiMeta!Discover the API: name, description, total doc count, the list of sections, and the endpoint.
sections[Section!]!List every section with its docCount and nested docs.
docs(section, search, limit)[Doc!]!Browse or filter pages by section and/or a free-text term (default limit 100).
doc(id, slug)DocFetch one page by id (e.g. "graphql/queries") or by site slug. Returns null if not found.
search(query!, limit)[Doc!]!Full-text search across title, description, and body (default limit 20).

A Doc carries everything about a page — id, path, slug, title, description, section, category, its headings outline (each with depth, text, and anchor for deep-linking), the Markdown body, and a wordCount. For example, doc(id: "graphql/index") resolves to this page at /docs/graphql in the graphql section.

The corpus is real and live: 49 docs across 7 sections — keen-extension (15), onboarding (10), organization (9), chat (7), graphql (6), tooling (1), and root (1).

Limits

The endpoint is open, but query complexity is bounded by graphql-armor (configured in graphql-server/index.mjs): maxDepth 10, maxAliases 20, maxTokens 1500, and a costLimit of 8000. Field suggestions are left on, and request batching is not supported. These limits are generous for normal reads — see Errors and limits for the exact behavior and how rejections look.

Where to go next

  • Running the API — install, start the server, and open GraphiQL.
  • Schema overview — the full SDL: Doc, Heading, Section, ApiMeta, and the root Query.
  • Queries — runnable curl examples for docs, doc, sections, search, and meta, with variables and response shapes.
  • Drive the docs from an agent — patterns for letting an AI agent introspect and query the docs cold.
  • Errors and limits — error envelope, validation, and the armor complexity limits.