Contributing
Contribute to ktx through code, docs, connectors, and examples.
ktx is an open-source context layer for data agents. The project welcomes focused contributions that improve setup, integrations, CLI behavior, documentation, connector coverage, and examples.
Where to start
| Goal | Start here |
|---|---|
| Prepare a local development checkout | Development setup |
| Understand the workspace layout | Repository structure |
| Run verification before a pull request | Running tests |
| Add a database connector | Adding a connector |
| Update docs for a user-visible CLI or setup change | PR guidelines |
Contribution areas
| Area | Good first context |
|---|---|
| CLI and setup | packages/cli, especially setup steps, command definitions, status checks, and smoke tests |
| Context engine | packages/context, including project config, ingest orchestration, and semantic search |
| Connectors | packages/connector-*, plus connector-specific tests and integration docs |
| Python semantic layer | python/ktx-sl for planning and SQL compilation |
| ktx daemon | python/ktx-daemon for the portable runtime API |
| Documentation | docs-site/content/docs for public docs and docs-site/tests for docs behavior |
Development setup
This page is for contributors working on the ktx repository. To install ktx for
an analytics project, use the published
@kaelio/ktx package in the
Quickstart.
Prerequisites
- Node.js 22+ and pnpm - for the TypeScript workspace
- Python 3.11+ and uv - for the Python semantic layer and daemon
- Git - for version control
Clone and install
git clone https://github.com/kaelio/ktx.git cd ktx pnpm install uv sync --all-groups
pnpm install sets up all TypeScript packages in the workspace.
uv sync --all-groups installs Python dependencies for the semantic layer and
daemon, including dev and test groups.
Build
pnpm run buildThis builds all TypeScript packages. You can also build individual packages:
pnpm --filter @ktx/cli run build pnpm --filter @ktx/context run build
Link the CLI for local testing
pnpm run setup:dev pnpm run link:dev
This makes the ktx-dev command available globally, pointing at your local
build. Use this development binary when you need to test unpublished repository
changes.
Repository structure
ktx is a pnpm + uv workspace. TypeScript packages live in packages/, Python
projects in python/.
packages/
cli/ # CLI entry point and commands
context/ # Core context engine (scan, ingest, MCP, semantic layer)
llm/ # LLM client abstraction
connector-postgres/ # PostgreSQL connector
connector-snowflake/ # Snowflake connector
connector-bigquery/ # BigQuery connector
connector-mysql/ # MySQL connector
connector-sqlserver/ # SQL Server connector
connector-sqlite/ # SQLite connector
connector-posthog/ # PostHog connector
python/
ktx-sl/ # Semantic layer - grain-aware query planning and SQL compilation
ktx-daemon/ # Daemon - portable API server around the semantic layer
examples/ # Example projects and fixtures
scripts/ # Workspace scripts (benchmarks, verification, release)
docs-site/ # Documentation site (Fumadocs)All TypeScript packages are ESM ("type": "module") and use NodeNext module
resolution. The Python projects use pyproject.toml for dependency management.
Running tests
TypeScript
# Run all tests pnpm run test # Run tests for a specific package pnpm --filter @ktx/cli run test pnpm --filter @ktx/context run test # Type-check all packages pnpm run type-check # Type-check a specific package pnpm --filter @ktx/context run type-check # CLI smoke test pnpm --filter @ktx/cli run smoke
Python
# Run all Python tests uv run pytest -q # Semantic layer tests uv run pytest python/ktx-sl/tests -q # Daemon tests uv run pytest python/ktx-daemon/tests -q
Pre-commit checks
After modifying Python files, run pre-commit on the changed files:
uv run pre-commit run --files python/ktx-sl/src/changed_file.py
Full verification
For cross-cutting changes that affect package exports or shared contracts:
pnpm run build pnpm run type-check pnpm run test uv run pytest -q
Adding a connector
Database connectors live in packages/connector-<name>/. Each connector
implements the KtxScanConnector interface from @ktx/context.
Step 1: Scaffold the package
Create a new directory at packages/connector-<name>/ with:
packages/connector-<name>/
package.json
tsconfig.json
src/
index.ts # Public exports
connector.ts # KtxScanConnector implementation
dialect.ts # SQL dialect handlingThe package.json should follow the pattern of existing connectors:
{ "name": "@ktx/connector-<name>", "private": true, "type": "module", "main": "dist/index.js", "types": "dist/index.d.ts", "exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } }, "dependencies": { "@ktx/context": "workspace:*" } }
Step 2: Implement the connector
Your connector class must implement KtxScanConnector, which requires:
id- a string identifier, typically"<driver>:<connectionId>"driver- theKtxConnectionDrivervalue for your databasecapabilities- aKtxConnectorCapabilitiesobject declaring what your connector supports:tableSampling,columnSampling,columnStats,readOnlySql,nestedAnalysis,eventStreamDiscovery,formalForeignKeys,estimatedRowCountsintrospect()- discovers tables, columns, types, and constraints, returning aKtxSchemaSnapshot
Optional methods for richer scanning:
sampleColumn()- sample values from a specific columnsampleTable()- sample rows from a tablecolumnStats()- compute column statisticsexecuteReadOnly()- execute arbitrary read-only SQL
Step 3: Add a dialect
The dialect class handles database-specific concerns: identifier quoting, type mapping from native types to normalized types, and query generation for sampling and statistics.
Step 4: Wire it up
Register the new connector in packages/context so the CLI and scan
engine can instantiate it. Look at how existing connectors are registered for
the pattern.
Step 5: Test
pnpm --filter @ktx/connector-<name> run build pnpm --filter @ktx/connector-<name> run type-check pnpm --filter @ktx/connector-<name> run test
Use packages/connector-sqlite/ as a minimal reference and
packages/connector-postgres/ as a full-featured one.
Code conventions
- TypeScript: strict types, no
any, noas unknown as. Usezodschemas for runtime validation at CLI and config boundaries. Follow thecamelCaseSchema/PascalCaseTypenaming convention for Zod schemas and inferred types. - Python: type hints on all new code,
pathliboveros.path, explicit exception types over broadexcept Exception,logger.exception()for caught exceptions. Usesqlglotfor SQL parsing - never regex. - Dependencies:
pnpmfor Node packages,uvfor Python. - Dead code: remove it. Don't leave commented-out code, unused wrappers, or empty directories.
PR guidelines
Before submitting a pull request:
- Run the relevant checks - at minimum,
pnpm run type-checkandpnpm run testfor TypeScript changes,uv run pytest -qanduv run pre-commit run --files [FILES]for Python changes. - Build if you changed exports - run
pnpm run buildto verify package exports anddist/expectations still align. - Keep changes focused - one logical change per PR. Don't bundle unrelated refactors.
- Follow existing patterns - match the style and conventions of surrounding code. The codebase favors explicit over clever.
- Update docs for user-visible changes - update
docs-site/content/docs/when setup, CLI, configuration, or integration behavior changes. - Don't commit artifacts -
node_modules/,.venv/,dist/, coverage output, and local databases should not be committed.
For larger features or architectural changes, open an issue first to discuss the approach.
Agent usage notes
Use this page when an agent is modifying the ktx repository itself rather than using ktx in an analytics project.
| Agent task | Command or section |
|---|---|
| Prepare the workspace | pnpm install, pnpm run setup:dev, uv sync --all-groups |
| Verify TypeScript changes | pnpm run type-check, pnpm run test, or package-filtered equivalents |
| Verify Python changes | uv run pytest -q and uv run pre-commit run --files <files> |
| Add a connector | Adding a connector |
| Check style expectations | Code conventions |
Common recovery path: if a check fails because generated files or local runtimes are missing, run the setup commands first. If a check fails because of a real type, lint, or test error, fix the source file and rerun the smallest failing check before broadening verification.