# What the catalog counts as a specification

Source: https://apigenie.pl/docs/concepts/what-the-catalog-counts-as-a-specification

`apigenie-catalog list` turns a repository into the list of its API specifications, with nothing
uploaded anywhere: the repository is the catalog. This page explains which files make the list
and why, how each one gets its name, and what the root of the catalog is; the
[apigenie-catalog](/docs/reference/catalog) page of the reference lists the options and the
output.

The examples use this repository:

```text
shop/
  .git/
  .gitignore                 build/
  apigenie.yaml
  apis/
    orders/
      openapi.yaml           openapi: 3.1.0, info.title: Orders API
      schemas/order.yaml     a schema the document references
    orders-v2.yaml           openapi: 3.1.0, info.title: Orders API, not committed yet
  examples/sample.yaml       openapi: 3.1.0, info.title: Example
  graphql/
    schema.graphql           type Query { ... }
    ping.graphql             query Ping { ping }
  proto/pricing.proto        package acme.pricing.v1
  build/out.yaml             ignored by git
```

## Which files are looked at

In a Git repository, the files Git tracks or would track: committed files, staged files, and new
files that no ignore rule excludes. `apis/orders-v2.yaml` is looked at before it is committed;
`build/out.yaml` never is. Outside Git, every file except those under a directory whose name
starts with a dot and under `node_modules`.

`catalog.exclude` in the configuration leaves more out, with glob patterns relative to the file:
`*` matches within a directory, `**` across directories.

```yaml
version: '1.0'
catalog:
  exclude:
    - "**/examples/**"
```

## Which of them are specifications

A file is a specification by what is in it, not by its name:

| Format | Files |
| --- | --- |
| OpenAPI, AsyncAPI, Swagger 2.0 | JSON and YAML files whose root has the `openapi`, `asyncapi` or `swagger` property |
| Protobuf | every `.proto` file |
| GraphQL | `.graphql`, `.graphqls` and `.gql` files with type definitions |

So `apis/orders/schemas/order.yaml`, a file of a split document that holds a schema and no
`openapi` property, is not listed: the document it belongs to is, by its root file.
`graphql/ping.graphql`, an operation document, is not listed either. A file that can't be read is
reported on the standard error and left out.

```text
$ apigenie-catalog list
NAME             FORMAT           VERSION  PATH                      COMMIT
orders-api       OpenAPI 3.1.0    1.3.0    apis/orders-v2.yaml       -
orders-api       OpenAPI 3.1.0    1.2.0    apis/orders/openapi.yaml  0d5d8a7 2026-10-29
schema           GraphQL          -        graphql/schema.graphql    0d5d8a7 2026-10-29
acme-pricing-v1  Protobuf proto3  -        proto/pricing.proto       0d5d8a7 2026-10-29
```

## How a specification is named

A name is derived from the document: `info.title` in lower case with dashes (`Orders API` is
`orders-api`), the Protobuf package (`acme.pricing.v1` is `acme-pricing-v1`), or the file name
for a GraphQL schema. Two files with the same derived name are both listed, with a line on the
standard error:

```text
2 specifications are named 'orders-api': apis/orders-v2.yaml, apis/orders/openapi.yaml; name them in the catalog section (apigenie-catalog init does)
```

A derived name changes with the title and says nothing about the owner. `apigenie-catalog init`
writes an entry per specification in `catalog.specs`, with a name that stays when the file moves
or its title changes, and an `owner` to fill in; a name two files would share gets a number:

```yaml
catalog:
  specs:
    - name: orders-api
      path: apis/orders-v2.yaml
      owner: null
    - name: orders-api-2
      path: apis/orders/openapi.yaml
      owner: null
```

The entries don't make the catalog: a specification the section doesn't list is still listed,
with its derived name, and `listed: false` in the JSON output tells the two apart.

## The root of the catalog

Paths are relative to the root of the catalog, in the output and in the configuration: the
directory of the configuration file, else the root of the Git repository, else the directory
given. The directory argument only narrows the search, and has to be inside the root:

```text
$ cd apis && apigenie-catalog list
NAME        FORMAT         VERSION  PATH                      COMMIT
orders-api  OpenAPI 3.1.0  1.3.0    apis/orders-v2.yaml       -
orders-api  OpenAPI 3.1.0  1.2.0    apis/orders/openapi.yaml  0d5d8a7 2026-10-29
```

The paths stay `apis/...`, since the root is still `shop/`.

## What the catalog is not

The catalog records what the repository holds. It doesn't check the specifications
([`apigenie lint`](/docs/reference/cli/lint) does), keep their versions (Git does, and
[`apigenie changelog`](/docs/reference/cli/changelog) reads them) or serve them.
`apigenie-catalog` is experimental: release tags, pinned consumers and a catalog across
repositories are planned, and its options can change before 1.0
([Compatibility](/docs/reference/cli/compatibility)).

## See also

- [apigenie-catalog](/docs/reference/catalog): the options of `list` and `init`, the columns
  and the JSON output.
- [Configuration](/docs/reference/cli/configuration#catalog): the `catalog` section.
- [Catalog the APIs of a repository](/docs/guides/catalog-the-apis-of-a-repository): the guide.
