Skip to content

Publish a registry

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

chkit uses the shadcn registry envelope 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.

For a minimal example, save this as registry/demo/index.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.

Save this as registry/registry.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.

Field under meta.chkitMeaning
formatVersionRegistry metadata format; currently 1
versionSemantic version of this template; immutable after publication
changelogNewest-first version history with a semantic version and nonempty changes array per entry; optional for custom and legacy items, required for official current manifests
languageCurrently typescript
licenseLicense for the copied source
documentationOptional HTTP(S) URL of the app’s integration guide; shown by CLI list and inspect
logoOptional HTTP(S) URL of the app’s logo; included in discovery metadata
chkit, ingest, clickhouseSupported CLI, ingestion package, and ClickHouse version ranges
root, entry, exportsInstallation directory, provider entry, and explicit public exports
resourcesResource names and descriptions, read scopes, sync strategy (full, timestamp, or cursor), optional title, default table, and endpoints with method, path, and provider documentation URL
authenticationAuthentication method, required env names, ordered setup steps, and the provider’s credential setup documentation URL
viewsDerived views with a name, source resource source, and description; these reuse synced records
syncSync description, external schedule, and deletions behavior
envEnvironment variable names mapped to example values, such as {"ATTIO_API_TOKEN": ""}
fileHashesSHA-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.

Keep a cumulative integration changelog in meta.chkit.changelog:

{
"version": "0.2.0",
"changelog": [
{
"version": "0.2.0",
"changes": ["Give People and Companies independent ingestion streams."]
},
{
"version": "0.1.2",
"changes": ["Include fixture tests and expanded authentication and resource metadata."]
}
]
}

The first entry matches the template version, and subsequent versions descend without duplicates. Retain notes for earlier releases, including migration details users need when upgrading. CLI inspect, integration guides, and agent-readable Markdown display this same history. Historical artifacts without the optional field remain valid. Older strict clients reject unknown metadata fields; current templates using changelog require a supporting CLI version.

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.

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

{
"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.

Terminal window
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:

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:

Terminal window
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.

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.

Each official provider has one self-contained directory:

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.

Use one pipeline per installation or account, with independent streams per resource type or configured collection. Attio People and Companies are separate streams sharing a raw records table; individual people remain records. Default to separate raw resource destinations with source and parent join keys, then combine them in warehouse views. A child reader may enumerate parents to reach a parent-scoped endpoint, but it owns that discovery and its checkpoints; parent publication does not wait for it. GitHub issues, PRs, comments, reviews, and commits follow this model. Embed children only for an explicit document model or an inseparable bounded provider object. Pipeline order cannot become a discovery dependency.

Prefer paginate() and the bundled incremental strategies. An ordinary full read uses fullSync() and the executor’s journaled completion, including empty reads; add provider state only for a justified contract such as sync-token promotion, delayed children, or expensive acknowledged-parent enrichment. Pipeline factories bind supplied configuration to both readers and strategies. Raw table exports remain setup-time schema definitions. Verify installed modular templates at relocated paths so missing transitive files cannot pass source-only tests.

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’s main branch and installs those 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.

An artifact already present in the PR’s merged base is immutable: preserve its exact bytes and path. Each integration contributes at most one new version artifact per PR. Choose its version above the latest merged release when first changing distributed source or metadata; subsequent edits in the same unmerged PR update that draft’s source and current changelog entry without another version bump. Intermediate PR revisions do not become separate release artifacts or changelog entries.

Regenerate the draft at the same version with the repository’s release command:

Terminal window
bun run registry:release -- --base origin/main attio
bun run check:registry-releases -- --base origin/main

The base defaults to origin/main; use the actual PR base when it differs. Pass provider names to refresh selected integrations, or omit names to refresh all current drafts. The release command regenerates artifacts from source and refuses to replace versions already in the base. The check rejects changed or deleted published artifacts, multiple new versions for one integration, and a current artifact that does not match its source and manifest. The same draft can be regenerated after every edit, including after it has been committed or pushed to the PR branch. Once merged, further template changes require a new version and changelog entry in another PR.

Commit the generated draft with its source, manifest, and changelog updates. Do not hand-edit artifact content 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.

Each provider declared in registry/<name>/manifest.json has an MDX guide at apps/docs/src/content/docs/integrations/<name>.mdx so the shared resource and changelog components render. 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, sync/deletion metadata, and an integration changelog. 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:

import RegistryReference from '../../../components/RegistryReference.astro';
<RegistryReference name="attio" section="authentication" />
<RegistryReference name="attio" section="scopes" />
<RegistryReference name="attio" section="resources" />
<RegistryReference name="attio" section="changelog" />

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. Include changelog under a Changelog heading in each official integration guide. Keep the explanation of provider-specific behavior as prose alongside the generated reference tables.

The integration list, 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.

Terminal window
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 changelog, and verify the guide appears in apps/docs/dist/_raw/index.md and apps/docs/dist/llms.txt. Changes to released template metadata require a new version just like source changes; edits to an unmerged draft update its one version artifact.