---
title: Publish a registry
description: Build and host versioned chkit templates containing editable schemas and ingestion source.
---

A registry distributes source files, package requirements, and provider metadata as static JSON artifacts.

## File format

chkit uses the [shadcn registry envelope](https://ui.shadcn.com/docs/registry/registry-json) with `registry:item` items and `registry:file` files. chkit-specific metadata lives under `meta.chkit`.

Format version 1 supports self-contained TypeScript templates. It does not resolve `registryDependencies`, transform UI imports, or run template installation hooks. Unknown fields and unsupported item types fail validation. A general shadcn UI registry is not a compatible chkit registry.

## Create a source template

For a minimal example, save this as `registry/demo/index.ts`:

```ts
import { definePipeline, defineStream, rawRows, rawTable } from '@chkit/plugin-ingest'

export const demoEventsRaw = rawTable({ database: 'default', name: 'demo_events_raw' })

const events = defineStream({
  id: 'demo.events',
  destination: demoEventsRaw,
  async *read() {
    yield { rows: rawRows([{ id: 'example', message: 'Registry installed' }], (event) => event.id) }
  },
})

export const demo = definePipeline({ id: 'demo', streams: [events] })
```

Use relative imports inside a larger provider directory so it remains movable with `chkit add --path`. The entry must explicitly export every schema object and active pipeline listed in the manifest; wildcard exports do not satisfy the builder's export check.

## Declare the catalog

Save this as `registry/registry.json`:

```json
{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "example-providers",
  "homepage": "https://example.com",
  "items": [
    {
      "name": "demo",
      "type": "registry:item",
      "title": "Demo",
      "description": "A local fixture source for testing registry installation.",
      "dependencies": [
        "@chkit/core@^0.2.0-beta.8",
        "@chkit/plugin-ingest@^0.2.0-beta.8"
      ],
      "files": [
        {
          "path": "demo/index.ts",
          "type": "registry:file",
          "target": "src/integrations/demo/index.ts"
        }
      ],
      "meta": {
        "chkit": {
          "formatVersion": 1,
          "version": "0.1.0",
          "language": "typescript",
          "license": "MIT",
          "chkit": "^0.2.0-beta.8",
          "ingest": "^0.2.0-beta.8",
          "clickhouse": ">=25.3.0",
          "root": "src/integrations/demo",
          "entry": "index.ts",
          "exports": ["demoEventsRaw", "demo"],
          "resources": [
            {
              "name": "events",
              "description": "One fixture event per full read.",
              "scopes": [],
              "strategy": "full"
            }
          ],
          "env": {}
        }
      }
    }
  ]
}
```

Each source `files[].path` is relative to the manifest's directory. `target` is the default consumer-project path and must sit inside `meta.chkit.root`. `entry` is relative to that root. Paths must be normalized relative paths without `..` segments.

The item name `registry` is reserved because `registry.json` contains the catalog.

## Metadata and dependencies

| Field under `meta.chkit` | Meaning |
|---|---|
| `formatVersion` | Registry metadata format; currently `1` |
| `version` | Immutable semantic version of this template |
| `language` | Currently `typescript` |
| `license` | License for the copied source |
| `documentation` | Optional HTTP(S) URL of the app's integration guide; shown by CLI list and inspect |
| `logo` | Optional HTTP(S) URL of the app's logo; included in discovery metadata |
| `chkit`, `ingest`, `clickhouse` | Supported CLI, ingestion package, and ClickHouse version ranges |
| `root`, `entry`, `exports` | Installation directory, provider entry, and explicit public exports |
| `resources` | Resource names and descriptions, read scopes, sync strategy (`full`, `timestamp`, or `cursor`), optional `title`, default `table`, and `endpoints` with `method`, `path`, and provider `documentation` URL |
| `authentication` | Authentication `method`, required `env` names, ordered `setup` steps, and the provider's credential setup `documentation` URL |
| `views` | Derived views with a `name`, source resource `source`, and `description`; these reuse synced records |
| `sync` | Sync `description`, external `schedule`, and `deletions` behavior |
| `env` | Environment variable names mapped to example values, such as `{"ATTIO_API_TOKEN": ""}` |
| `fileHashes` | SHA-256 values keyed by target path; generated by the builder |

Resource strategies describe selection: `full` performs complete scan cycles, including scans with completion checkpoints; `timestamp` selects time windows; `cursor` follows checkpointed provider state, such as a change token or a resumable snapshot traversal. Describe restart behavior, cursor lifetime, and deletion handling in `sync`. Metadata does not configure the runtime strategy. Older strict registry clients accept only `full`; templates advertising new labels must require a CLI version that accepts them.

Declare npm dependencies as `package@semver-range`. Every item must include `@chkit/core` and `@chkit/plugin-ingest`. Git URLs, local dependencies, and package-manager aliases are outside this format.

Use blank values for secrets in `env`. Never include credentials in metadata or source artifacts. State resource limitations in the item's description and copied README, including deletion behavior and inaccessible API families.

### Package fixture tests

Keep tests under the provider's `tests/` directory and mark their file entries with `role: "test"`:

```json
{
  "path": "demo/tests/demo.test.ts",
  "type": "registry:file",
  "target": "src/integrations/demo/tests/demo.test.ts",
  "role": "test"
}
```

These files receive content hashes like other source files; the installer includes them only with `--with-tests`. Optional item-level `devDependencies` lists test tooling, such as `@types/bun@^1.2.0`, using the same `package@semver-range` format. Those dependencies are added to the consumer's development dependencies only when tests are selected.

Tests should use fixture payloads and mocked service clients so consumers can run them without provider credentials. Avoid repository-relative imports, unpublished workspace tooling, and live-database prerequisites in the distributed test set. Repository-only packaging or database tests can live in the same source folder, excluded from the manifest's files.

## Build and test locally

```sh
chkit registry build registry/registry.json --output ./registry-output
chkit registry list --registry ./registry-output
chkit registry inspect demo --registry ./registry-output
```

The build emits:

```text
registry-output/
  registry.json
  demo.json
  demo/
    0.1.0.json
```

`registry.json` is the discoverable catalog. `demo.json` points consumers to the current item contents. `demo/0.1.0.json` contains that specific version. Built items include source content and its hashes, so installation does not need access to the source repository.

From a separate test project with `package.json`, preview installation and then inspect the copied code:

```sh
chkit add /absolute/path/to/registry-output/demo/0.1.0.json --dry-run
chkit add /absolute/path/to/registry-output/demo/0.1.0.json --yes
chkit ingest list
chkit generate --name add-demo
```

Registry validation checks packaging and declared entry exports. Test each provider's pagination, errors, identities, and replay behavior with fixtures; validate the generated schema and queries against a development database before publishing.

## Publish immutable versions

Host the output directory on an HTTP(S) static host. Consumers can use its catalog URL with `--registry` or install a built item URL directly.

Keep every published `<name>/<version>.json` available. The builder rejects an attempt to write different bytes to an existing version file. Increment `meta.chkit.version` for any released template change, including source, dependencies, or metadata. Preserve older version files when building a deployment from a clean checkout; an empty output directory alone cannot establish what was previously published.

### Provider layout in the chkit repository

Each official provider has one self-contained directory:

```text
registry/
  attio/
    manifest.json
    README.md
    index.ts
    client.ts
    config.ts
    pipeline.ts
    sources/
      objects.ts
      object-attributes.ts
      records.ts
      lists.ts
      list-attributes.ts
      entries.ts
      notes.ts
      tasks.ts
      members.ts
    tests/
      attio.test.ts
      fixtures.ts
      install.e2e.test.ts
    releases/
      0.1.0.json
      0.1.1.json
      0.1.2.json
```

Each `sources/` module keeps a resource's reader and schema together. Shared request behavior stays in `client.ts`; selection and destination settings stay in `config.ts`.

`manifest.json` contains one registry item. Its source paths are relative to the provider directory (for example, `sources/notes.ts`); target paths still use the full consumer path such as `src/integrations/attio/sources/notes.ts`. The repository's catalog loader discovers these provider-local manifests and aggregates them for the build, CLI artifacts, and documentation. `bun scripts/build-registry.ts` builds the official catalog; it does not require a handwritten catalog at the registry root.

Released artifacts are committed under `registry/<name>/releases/<version>.json`. The official CLI reads provider directories and manifests from GitHub and installs those committed release artifacts directly. The documentation build also copies that history into `apps/docs/public/r/<name>/` before building the current catalog and latest aliases. History and the source are colocated without installing release files into consumer projects.

After validating a new release artifact, copy its immutable file into the provider's `releases/` directory and commit it with the corresponding source and version change. Do not hand-edit the artifact or commit generated latest aliases. Adding a provider or template version does not require an npm package release; changes to CLI behavior do. The docs build also publishes a static catalog at `https://chkit.obsessiondb.com/r/registry.json` for web and custom-registry use.

## Add an app to the official documentation

Each provider declared in `registry/<name>/manifest.json` has a guide at `apps/docs/src/content/docs/integrations/<name>.md` or `.mdx`. Set its title to `Integrating ClickHouse with <App title>` and write a specific one-sentence description. Give the sidebar a short app label.

Set `meta.chkit.documentation` to `https://chkit.obsessiondb.com/integrations/<name>/`. Every official app requires a provider logo: store the official asset in `apps/docs/public/logos/`, record its source in that directory's `README.md`, and set `meta.chkit.logo` to its full HTTPS URL on the docs site. Preserve the asset's proportions and brand colors.

Every official manifest includes authentication setup steps, resource titles and destination tables, provider endpoint references, derived views, and sync/deletion metadata. Credential setup must explain where an administrator creates a token in the source system, which permissions it requires, and how the execution environment receives it. Link to the provider's current instructions and verify the UI path before publishing.

Every guide also explains installation, migrations, raw and projected fields, pagination, repeat runs, failure recovery, unsupported data, and scheduling. Verify the claims against the installed readers and schema. A name-swapped introduction alone is not a complete integration guide.

Use `RegistryReference` in MDX to render shared reference sections from the provider manifest:

```mdx
import RegistryReference from '../../../components/RegistryReference.astro';

<RegistryReference name="attio" section="authentication" />
<RegistryReference name="attio" section="scopes" />
<RegistryReference name="attio" section="resources" />
```

The other sections are `overview`, `views`, and `sync`. The raw-Markdown build expands the same components for agents. The `resources` section documents every declared resource; handwritten guides must include each exact resource name in backticks. Keep the explanation of provider-specific behavior as prose alongside the generated reference tables.

The [integration list](/integrations/), its agent-readable Markdown, CLI discovery, and search structured data read the same manifest. The docs build checks that every official item has its guide, description, resource coverage, and required local logo asset. New guides also enter site search, the sitemap, and `llms.txt` automatically.

```sh
bun run scripts/check-registry-docs.ts
bun run --cwd apps/docs build
```

Preview the app listing and guide in both themes, check the rendered resource tables, and verify the guide appears in `apps/docs/dist/_raw/index.md` and `apps/docs/dist/llms.txt`. Metadata changes require a new immutable registry version just like source changes.

## Related pages

- [`chkit registry`](/cli/registry/): command reference and build flags.
- [`chkit add`](/cli/add/): consumer installation behavior.
- [Test a source](/api-sync/testing/): ingestion correctness beyond packaging.
- [Provider templates](/api-sync/templates/): template ownership and customization.
