Ch-kit – OS ClickHouse schema management and migrations, TypeScript and Python

lgvdp2 pts1 comments

chkit is now available in Python | chkit Docs<br>Skip to content<br>Search CtrlK Cancel

Star

chkit is now available in Python

Aug 11, 2026 - 6 min read<br>Lucas García de Viedma (ObsessionDB)

We closed our last post with a promise: if you do not use TypeScript but Python, a port was coming. It shipped.

Terminal windowpip install chkit-py

chkit --help

That is the entire ClickHouse® schema-as-code toolkit, ported to Python at parity with the TypeScript original: the DSL, the diff engine, the migration planner, the drift detection, the CI gates, and the plugins. It is not a wrapper around a Node binary. A wrapper would still put a Node runtime in your Airflow images and give Python nothing importable. It is a full port, with Pydantic models, a library API, and a CLI that is just chkit on your PATH.

This post covers why we built it, how the two implementations stay in sync, and what is different on the Python side.

The people closest to ClickHouse write Python<br>Section titled “The people closest to ClickHouse write Python”

Look at who actually sits next to a ClickHouse cluster all day. Data engineers orchestrating pipelines in Airflow and Dagster. Analytics engineers living in notebooks. ML teams whose entire world is pandas, Polars, and PyArrow. The queries feeding your dashboards were probably prototyped in a Jupyter cell.

For that whole population, a schema tool that only exists on npm is a tax. Adopting chkit meant adopting a Node toolchain (package.json, a runtime, a lockfile) in repositories that had none, maintained by people who did not choose JavaScript and should not have to. Most teams do the rational thing instead: they keep hand-writing DDL, which is exactly the failure mode chkit exists to eliminate.

Agents default to Python<br>Section titled “Agents default to Python”

Coding agents are the other reason. Ask an agent to script something against a database and it almost always writes Python, because that is the ecosystem it draws from.

If your schema toolkit does not exist in Python, agents route around it: they hand-write the CREATE TABLE, and you are back to unreviewed DDL, the exact problem chkit exists to solve. If you want agents to keep schema changes inside the migration workflow, the tool has to exist in the language they actually use.

The docs follow the same idea. Every page of chkit.obsessiondb.com is available as raw Markdown (append .md to any URL), there is an llms.txt index at the root, and every reference page now shows TypeScript and Python side by side with synced tabs: pick your language once, and the whole site follows. An agent (or a human) landing anywhere in the docs gets working code in the language it is actually going to run.

The same schema, in Python<br>Section titled “The same schema, in Python”

Here is the table from our last post, in Python:

from chkit import schema, table

events = table(

database="analytics",

name="events",

columns=[

{"name": "id", "type": "UInt64"},

{"name": "org_id", "type": "String"},

{"name": "source", "type": "LowCardinality(String)"},

{"name": "payload", "type": "String", "nullable": True},

{"name": "received_at", "type": "DateTime64(3)", "default": "fn:now64(3)"},

],

engine="MergeTree()",

primary_key=["id"],

order_by=["org_id", "received_at", "id"],

partition_by="toYYYYMM(received_at)",

ttl="received_at + INTERVAL 90 DAY",

settings={"index_granularity": 8192},

indexes=[

{"name": "idx_source", "expression": "source", "type": "set", "maxRows": 0, "granularity": 1},

],

definitions = schema(events)

Definitions are Pydantic models: frozen, validated at construction, unknown fields rejected. A typo in a column option fails loudly at import time instead of silently shipping a table with no codec. The DSL accepts both snake_case and the TypeScript camelCase names (primary_key or primaryKey), so examples port between languages with their keys unchanged.

The CLI is the same CLI. Same commands, same flags, same exit codes, same --json envelopes:

Terminal windowchkit generate --name add_events_table

chkit migrate # shows the plan

chkit migrate --apply # applies, journals, verifies checksums

chkit drift

chkit check --strict # your CI gate

Everything from the last post carries over. The guardrails: risk-tagged plans, the structural-vs-alterable distinction, tracked renames, destructive-operation blocking with exit code 3, checksum-verified migration history. The schema surface: dictionaries, refreshable materialized views, projections, ON CLUSTER mode. The ecosystem: pull for adopting an existing database (a built-in command in Python, no plugin to install), the codegen plugin (which emits Pydantic models, one shape covering what TypeScript needed interfaces and Zod for), the backfill engine, and the ObsessionDB integration.

Two implementations, one source of truth<br>Section titled “Two implementations, one source of truth”

A second implementation is only useful if the two never disagree. chkit-py and chkit share their...

python chkit schema name typescript type

Related Articles