openapi: 3.1.0
info:
  title: tabnas.dev
  summary: The machine-readable surface of the tabnas documentation site.
  description: |-
    tabnas is a parsing engine for any language. Grammars are data: you extend one that already works instead of starting over, and an agent can write one directly.

    This document describes what tabnas.dev serves to programs: the site index an agent
    should read first, the package and error-code catalogues, the MCP handshake, and the
    hosted MCP endpoint that runs the engine's tools over HTTP.

    Two things are true of every tabnas.dev operation and are not repeated on each one.
    First, the site is read-only and unauthenticated: GET and HEAD are the only methods,
    there are no keys, quotas or rate limits, and any other method answers 405 with the
    error object below. Second, every documentation page is content-negotiated — send
    `Accept: text/markdown` and the same URL returns clean markdown instead of HTML, with
    `Vary: Accept` set (acceptmarkdown.com). Appending `.md` to a page path fetches the
    same markdown without a header, and that form is described by getPageMarkdown below.

    The engine these endpoints describe is @tabnas/parser 0.8.11.
  version: 0.8.11
  contact:
    name: tabnas maintainers
    email: richard@ricebridge.com
    url: https://tabnas.dev/contact/
  license:
    name: MIT
    identifier: MIT
  x-maintainer:
    name: Richard Rodger
    url: https://richardrodger.com
externalDocs:
  description: Documentation hub
  url: https://tabnas.dev/docs/
servers:
  - url: https://tabnas.dev
    description: The documentation site. Read-only, unauthenticated.
tags:
  - name: index
    description: "Where an agent starts: the site index and this document."
  - name: catalogue
    description: "Generated catalogues: package versions, packages, error codes."
  - name: content
    description: Documentation pages as markdown.
  - name: mcp
    description: "Model Context Protocol: the manifest here, and the hosted server."
paths:
  /llms.txt:
    get:
      operationId: getLlmsIndex
      summary: The llms.txt site index
      description: "The llmstxt.org index for this site: one line per page with a short description of what is on it, the installable agent distributions, and the notes an agent should read before writing a grammar. Read this first."
      tags:
        - index
      responses:
        "200":
          description: The index, as markdown-flavoured plain text.
          content:
            text/plain:
              schema:
                type: string
  /llms-full.txt:
    get:
      operationId: getLlmsFull
      summary: Every documentation page in one file
      description: The full text of the documentation and how-to collections, concatenated in site order, so a model can read the documentation without following links.
      tags:
        - index
      responses:
        "200":
          description: The full documentation text.
          content:
            text/plain:
              schema:
                type: string
  /openapi.json:
    get:
      operationId: getOpenApiJson
      summary: This document, as JSON
      description: The OpenAPI 3.1 description of every endpoint listed here.
      tags:
        - index
      responses:
        "200":
          description: An OpenAPI 3.1 document.
          content:
            application/json:
              schema:
                type: object
  /openapi.yaml:
    get:
      operationId: getOpenApiYaml
      summary: This document, as YAML
      description: The same OpenAPI 3.1 document, serialised as YAML.
      tags:
        - index
      responses:
        "200":
          description: An OpenAPI 3.1 document.
          content:
            application/yaml:
              schema:
                type: string
  /versions.json:
    get:
      operationId: getVersions
      summary: The package versions this documentation describes
      description: The site's own dependency pins, which are the versions every example on the site was executed against. Use this to check whether a page describes the release you are running.
      tags:
        - catalogue
      responses:
        "200":
          description: The pinned versions.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Versions"
  /packages.json:
    get:
      operationId: getPackages
      summary: The package catalogue
      description: "Every package in the project: its tier, what it parses or does, the recorded release, and whether it ships as an npm package, a Go module, or both. Recorded releases can lag the registry — /versions.json is the exact answer for the versions this documentation describes."
      tags:
        - catalogue
      responses:
        "200":
          description: The catalogue.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PackageCatalogue"
  /errors.json:
    get:
      operationId: getErrorRegistry
      summary: Every error code the engine and its plugins raise
      description: The full error registry. A parse failure carries a `code`, and that code — not the message text — is the contract across the TypeScript and Go runtimes. Match on the code, then look it up here for the hint and the declaring package.
      tags:
        - catalogue
      responses:
        "200":
          description: The registry.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorRegistry"
  /errors/{code}.json:
    get:
      operationId: getErrorCode
      summary: One error code
      description: "The registry entry for a single error code: its message template, the hint explaining what causes it, which runtimes raise it, and the human page for it."
      tags:
        - catalogue
      parameters:
        - name: code
          in: path
          required: true
          description: The error code, exactly as it appears in a diagnostic.
          schema:
            type: string
            enum: &a1
              - bad_entity_ref
              - cancel
              - cdata_terminator_in_text
              - comment_double_dash
              - csv_extra_field
              - csv_missing_field
              - duplicate_attribute
              - duplicate_section
              - end_of_source
              - external_entity_in_attr
              - grammar
              - handle
              - internal
              - invalid_ascii
              - invalid_namespace_uri
              - invalid_unicode
              - invalid_xml_char
              - json5_empty
              - json5_no_value
              - lt_in_attr_value
              - multisource_cycle
              - multisource_not_found
              - pi_target_invalid
              - reserved_namespace
              - text_at_top_level
              - unbound_prefix
              - undeclared_entity
              - unexpected
              - unknown
              - unknown_rule
              - unparsed_entity_ref
              - unprintable
              - unterminated_cdata
              - unterminated_comment
              - unterminated_doctype
              - unterminated_pi
              - unterminated_section
              - unterminated_string
              - usage
              - xml_invalid_tag
              - xml_mismatched_tag
              - zon_char
              - zon_doc_comment
              - zon_dup_field
              - zon_ident
              - zon_number
          example: unexpected
      responses:
        "200":
          description: The entry.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorCodeDocument"
        "404":
          description: No such error code. The full list is at /errors.json.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
  /.well-known/mcp:
    get:
      operationId: getMcpManifest
      summary: How to connect an agent over MCP
      description: "The MCP handshake for this domain: both transports (local stdio via npx, and the hosted streamable-HTTP endpoint), the tools and resources the server exposes, and the registry name the server is published under."
      tags:
        - mcp
      responses:
        "200":
          description: The manifest.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/McpManifest"
  /{page}.md:
    get:
      operationId: getPageMarkdown
      summary: Any documentation page, as markdown
      description: "Every page on this site has a markdown twin at its own path plus `.md`, generated from the page that shipped. `Accept: text/markdown` on the page URL returns the same bytes; this form is for callers that would rather not set a header. The home page is /index.md."
      tags:
        - content
      parameters:
        - name: page
          in: path
          required: true
          description: The page path without its leading slash and without a trailing slash — `why`, `docs/quickstart`, `how-to/parse-errors`, `errors/unexpected`. May contain slashes. `index` is the home page.
          schema:
            type: string
            pattern: ^[a-z0-9]+(?:[-/][a-z0-9_]+)*$
          examples:
            home:
              value: index
            agentGuide:
              value: agents
            quickstart:
              value: docs/quickstart
      responses:
        "200":
          description: The page as markdown, with a small YAML frontmatter block carrying its title, description and canonical URL.
          content:
            text/markdown:
              schema:
                type: string
        "404":
          description: No such page. /sitemap-index.xml lists every page.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
  /health:
    get:
      operationId: getMcpHealth
      summary: Hosted MCP endpoint liveness
      description: A liveness check for the hosted MCP server, reporting its running version.
      tags:
        - mcp
      servers:
        - url: https://mcp.tabnas.dev
          description: The hosted MCP endpoint.
      responses:
        "200":
          description: The service is up.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Health"
  /mcp:
    post:
      operationId: callMcpTool
      summary: Call the hosted MCP server
      description: |-
        The Model Context Protocol over streamable HTTP, as JSON-RPC 2.0. Standard MCP
        methods apply: `initialize`, `tools/list`, `tools/call`, `resources/list`,
        `resources/read`.

        The server exposes 7 tools — parse, validate_grammar, explain_parse_error, test_grammar, list_plugins, describe_plugin, compare_grammars —
        and the fleet's contract files as resources. Full tool schemas come from
        `tools/list`; the tools and their contracts are documented at https://tabnas.dev/mcp/.

        Local stdio is the recommended transport (`npx --yes @tabnas/mcp mcp`): free,
        private, unlimited, and the same code. This endpoint exists for clients that
        cannot spawn a process, and it is bounded — a 256 KB request body cap and a
        per-IP rate limit, both reported by /.well-known/mcp. Document content is never
        logged, stored or used for training.
      tags:
        - mcp
      servers:
        - url: https://mcp.tabnas.dev
          description: The hosted MCP endpoint.
      requestBody:
        required: true
        description: A JSON-RPC 2.0 request.
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/JsonRpcRequest"
            examples:
              initialize:
                summary: Open a session
                value:
                  jsonrpc: "2.0"
                  id: 1
                  method: initialize
                  params:
                    protocolVersion: 2025-06-18
                    capabilities: {}
                    clientInfo:
                      name: example-client
                      version: 1.0.0
              listTools:
                summary: List the tools and their schemas
                value:
                  jsonrpc: "2.0"
                  id: 2
                  method: tools/list
              validateGrammar:
                summary: Check a serialized grammar before running it
                value:
                  jsonrpc: "2.0"
                  id: 3
                  method: tools/call
                  params:
                    name: validate_grammar
                    arguments:
                      grammar: {}
      responses:
        "200":
          description: A JSON-RPC 2.0 response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/JsonRpcResponse"
        "405":
          description: The endpoint is POST-only; a GET says so.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "413":
          description: The request body exceeded the 256 KB cap.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "429":
          description: The per-IP rate limit was exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
components:
  schemas:
    Error:
      type: object
      description: The error shape every tabnas.dev endpoint returns for a request it cannot answer. `code` is stable and safe to branch on; `message` and `hint` are for a reader, human or otherwise.
      required:
        - error
      properties:
        error:
          type: object
          required:
            - status
            - code
            - message
            - hint
          properties:
            status:
              type: integer
              description: The HTTP status, repeated in the body.
              examples:
                - 404
                - 405
                - 406
            code:
              type: string
              description: A stable machine-readable reason.
              enum:
                - not_found
                - method_not_allowed
                - not_acceptable
            message:
              type: string
              description: The HTTP reason phrase.
            hint:
              type: string
              description: What to do instead. Written to be actionable, not decorative.
            documentation:
              type: string
              format: uri
            openapi:
              type: string
              format: uri
            resources:
              type: object
              description: The site's entry points, so a lost caller can recover in one hop.
              additionalProperties:
                type: string
                format: uri
    Versions:
      type: object
      required:
        - site
        - engine
        - packages
      properties:
        $comment:
          type: string
        site:
          type: string
          format: uri
        engine:
          type:
            - string
            - "null"
          description: The @tabnas/parser version this documentation describes.
          examples:
            - 0.8.11
        packages:
          type: object
          description: Every @tabnas package the site depends on, at an exact version.
          additionalProperties:
            type: string
    PackageCatalogue:
      type: object
      required:
        - site
        - count
        - packages
      properties:
        $comment:
          type: string
        site:
          type: string
          format: uri
        count:
          type: integer
        tiers:
          type: object
          description: The tier keys used below, and the label each one carries on the site.
          additionalProperties:
            type: string
        packages:
          type: array
          items:
            $ref: "#/components/schemas/Package"
    Package:
      type: object
      required:
        - name
        - tier
        - description
        - version
        - npm
        - go
      properties:
        name:
          type: string
          description: The bare package name, without the scope.
        tier:
          type: string
          description: What kind of package it is.
          enum:
            - engine
            - tooling
            - agent
            - grammar
            - plugin
            - cli
        description:
          type: string
        version:
          type: string
          description: The recorded release. Can lag the registry; /versions.json is exact.
        npm:
          type:
            - string
            - "null"
          description: The npm package name, or null if it does not ship to npm.
        go:
          type:
            - string
            - "null"
          description: The Go module path, or null if it does not ship as a Go module.
        repository:
          type: string
          format: uri
    ErrorRegistry:
      type: object
      required:
        - site
        - engine
        - codes
      properties:
        $comment:
          type: string
        site:
          type: string
          format: uri
        engine:
          type: string
          description: The parser release the engine codes were generated from.
        count:
          type: integer
        codes:
          type: array
          items:
            $ref: "#/components/schemas/ErrorCode"
    ErrorCode:
      type: object
      description: One registry entry, exactly as src/errors.ts assembles it. A code can be declared in three places — the engine's own catalogue, a grammar plugin's descriptor, and a plugin's C ABI — and two codes in the fleet are claimed by more than one, so the three are separate fields rather than one `source`.
      required:
        - code
        - message
        - hint
        - runtime
        - engine
        - packages
        - abi
        - url
      properties:
        code:
          type: string
          description: The cross-runtime contract. Branch on this, never on the message.
          enum: *a1
        message:
          type:
            - string
            - "null"
          description: The message template, with `{name}` placeholders filled from the diagnostic. Null for a code declared only by a plugin or by a C ABI.
        hint:
          type:
            - string
            - "null"
          description: What causes it, and what to do about it. Null where the message is null.
        runtime:
          type:
            - string
            - "null"
          description: Which runtimes raise it. Null for a code the engine does not declare.
          enum:
            - both
            - ts
            - go
            - null
        engine:
          type: boolean
          description: Raised by the engine itself, so any grammar can produce it.
        packages:
          type: array
          description: Grammar plugins that declare this code in their descriptor.
          items:
            type: string
        abi:
          type: array
          description: "Packages whose C ABI declares this code. A different envelope from a parse diagnostic: an ABI code comes back from a call into a libtabnas* library."
          items:
            type: string
        url:
          type: string
          format: uri
          description: The human page for this code.
    ErrorCodeDocument:
      description: "What /errors/{code}.json returns: one entry, plus the two fields every generated document on this site carries."
      allOf:
        - $ref: "#/components/schemas/ErrorCode"
        - type: object
          properties:
            $comment:
              type: string
            site:
              type: string
              format: uri
    McpManifest:
      type: object
      required:
        - name
        - servers
        - tools
      properties:
        $comment:
          type: string
        name:
          type: string
        version:
          type:
            - string
            - "null"
          description: The @tabnas/mcp release the stdio command pins.
        description:
          type: string
        registry:
          type: object
          description: Where the server is published in the official MCP registry.
          properties:
            name:
              type: string
              examples:
                - dev.tabnas/mcp
            url:
              type: string
              format: uri
        servers:
          type: object
          description: One entry per transport, in the shape an MCP client's configuration takes.
          additionalProperties:
            type: object
            properties:
              type:
                type: string
                enum:
                  - stdio
                  - streamable-http
              command:
                type: array
                items:
                  type: string
              url:
                type: string
                format: uri
        transport:
          type: string
          enum:
            - stdio
            - streamable-http
        endpoint:
          type:
            - string
            - "null"
          format: uri
          description: The hosted streamable-HTTP endpoint.
        local:
          type:
            - string
            - "null"
          description: The recommended local stdio command.
          examples:
            - npx --yes @tabnas/mcp mcp
        tools:
          type: array
          items:
            type: string
        cli:
          type: object
          description: The command-line tool the same package installs. Every subcommand mirrors one MCP tool, and --json prints the bytes that tool returns.
          properties:
            command:
              type: string
              examples:
                - tabnas
            package:
              type: string
            install:
              type: string
            subcommands:
              type: array
              items:
                type: string
            documentation:
              type: string
              format: uri
        skills:
          type: array
          description: The Agent Skills that ship alongside the server.
          items:
            type: string
        package:
          type: string
          format: uri
        documentation:
          type: string
          format: uri
        handshake:
          type: string
          format: uri
          description: The running service's own manifest, which reports its live version, resource URIs and current limits.
        privacy:
          type: string
    Health:
      type: object
      required:
        - ok
        - service
      properties:
        ok:
          type: boolean
        service:
          type: string
          examples:
            - tabnas-mcp
        version:
          type: string
    JsonRpcRequest:
      type: object
      required:
        - jsonrpc
        - method
      properties:
        jsonrpc:
          type: string
          const: "2.0"
        id:
          type:
            - string
            - integer
        method:
          type: string
          description: An MCP method.
          examples:
            - initialize
            - tools/list
            - tools/call
            - resources/read
        params:
          type: object
          additionalProperties: true
    JsonRpcResponse:
      type: object
      required:
        - jsonrpc
      properties:
        jsonrpc:
          type: string
          const: "2.0"
        id:
          type:
            - string
            - integer
            - "null"
        result:
          type: object
          additionalProperties: true
        error:
          type: object
          properties:
            code:
              type: integer
            message:
              type: string
            data: {}
x-mcp:
  manifest: https://tabnas.dev/.well-known/mcp
  registry: dev.tabnas/mcp
  stdio:
    type: stdio
    command:
      - npx
      - --yes
      - "@tabnas/mcp@0.1.15"
      - mcp
  http:
    type: streamable-http
    url: https://mcp.tabnas.dev/mcp
x-llms-txt: https://tabnas.dev/llms.txt
x-repository: https://github.com/tabnas/web
x-package-count: 30
