Integrating ClickHouse with Attio
Sync Attio into ClickHouse to query CRM records, relationships, list membership, notes, and tasks alongside product or business data.
The app registry installs the Attio integration as editable TypeScript source. It includes nine raw tables, separate streams for each configured object type or list, workspace-wide resource streams, and three SQL views for people, companies, and deals. The default configuration creates nine streams writing to seven resource tables; entries and list-attribute readers require configured lists. Every run performs full reads through the Attio REST API and updates the latest observed versions in ClickHouse.
| Property | Included behavior |
|---|---|
| Registry app | attio (v0.2.0) |
| Install command | bunx chkit add attio |
| Source directory | src/integrations/attio |
| Authentication | Bearer token |
| Environment variables | ATTIO_API_TOKEN |
| ClickHouse | >=25.3.0 |
| Coverage | 9 synced resources, 3 derived views |
| Sync strategy | Full scans |
Install the Attio integration
Section titled “Install the Attio integration”Run these commands in a TypeScript project with a package.json. Use a chkit release that includes the registry and ingestion plugin; the examples use the beta release.
bun add -d chkit@betabunx chkit registry inspect attiobunx chkit add attio --dry-runbunx chkit add attioThe installer copies the provider source, installs compatible dependencies, registers the ingestion plugin, and connects the exported schemas and pipeline to the project’s config. An existing project’s schema definitions and connection settings remain in place. See installation behavior for supported config shapes and conflicts.
add prepares the project. Migrations create the ClickHouse objects, and ingest run performs the API calls. The registry is only used to obtain source files; subsequent syncs execute the installed code.
Configure the ClickHouse connection
Section titled “Configure the ClickHouse connection”For a new project, the generated clickhouse.config.ts has this shape:
import { defineConfig } from '@chkit/core'import { ingest } from '@chkit/plugin-ingest'
export default defineConfig({ entry: './src/integrations/attio/index.ts', plugins: [ingest()], clickhouse: { url: process.env.CLICKHOUSE_URL ?? 'http://localhost:8123', username: process.env.CLICKHOUSE_USER ?? 'default', password: process.env.CLICKHOUSE_PASSWORD ?? '', database: process.env.CLICKHOUSE_DB ?? 'default', },})Set the connection variables for the intended target. Keep the existing entry, schema paths, and plugins when adapting an existing project. Ingestion requires a direct connection; workbench-only authentication does not provide an ingestion destination.
The copied config.ts separately controls the database of the Attio tables and views. Set its database to the intended destination too; changing CLICKHOUSE_DB alone does not rename those schema objects.
Create an Attio API key
Section titled “Create an Attio API key”A workspace admin creates a single-workspace access token in Attio. The following steps use Attio’s API-key setup instructions:
- As a workspace admin, open the workspace-name dropdown in Attio and select Workspace settings.
- Open Developers, select + New access token, and name the token (for example, chkit ClickHouse).
- Grant the read scopes listed for the resources to sync.
- Click the token on the Developers page to copy it. Set ATTIO_API_TOKEN in the project .env file or the scheduler secret environment.
Grant read access to the categories required by the enabled streams. The scope table covers all supported resources; list-entry and list-attribute readers run only when lists is configured. No write scopes are needed.
| Resource | Required scopes |
|---|---|
| Objects | object_configuration:read |
| Object attributes | object_configuration:read |
| Records | object_configuration:read, record_permission:read |
| Lists | list_configuration:read |
| List attributes | list_configuration:read |
| List entries | list_configuration:read, list_entry:read |
| Notes | note:read, object_configuration:read, record_permission:read |
| Tasks | task:read, object_configuration:read, record_permission:read, user_management:read |
| Workspace members | user_management:read |
Configure the token in the project and scheduler
Section titled “Configure the token in the project and scheduler”Set the copied token in the project’s .env, replacing the placeholder:
ATTIO_API_TOKEN=replace-with-the-access-token-from-attioBun loads the project’s .env; a scheduler must supply ATTIO_API_TOKEN through its own secret or environment configuration, together with the ClickHouse connection variables. The installer writes required names to .env.example, which does not load credentials. Keep real tokens out of source control.
The reader sends the token in an Authorization: Bearer header when a request runs. Schema inspection, migration generation, and ingest list do not need an Attio token. An existing OAuth access token also works, but this integration does not obtain or refresh OAuth tokens; see Attio authentication.
A token’s permissions also determine which data the API returns. A 401 or 403 fails the affected stream with a diagnostic; the reader does not turn a permission error into an empty result.
Choose objects, lists, and destination names
Section titled “Choose objects, lists, and destination names”The installed src/integrations/attio/config.ts starts with:
export interface AttioConfig { sourceId: string database: string tablePrefix: string objects: readonly string[] lists: readonly string[] pageSize: number notesPageSize: number}
export const attioConfig: AttioConfig = { sourceId: 'attio.primary', database: 'default', tablePrefix: 'attio', objects: ['people', 'companies'], lists: [], pageSize: 500, notesPageSize: 50,}| Setting | Effect |
|---|---|
sourceId | Stable, non-secret identity used in stream IDs and row IDs |
database | Database containing the nine raw tables and three views |
tablePrefix | Prefix used before _records_raw, _people, and the other suffixes |
objects | Explicit object API slugs or UUIDs; default ['people', 'companies']; creates records and attribute streams per type |
lists | Explicit list API slugs or UUIDs; default []; creates entries and attribute streams per list |
pageSize | Positive integer, default 500, for attributes, records, entries, and tasks |
notesPageSize | Positive integer up to 50, default 50, for notes |
Add deals or a custom slug to objects to collect that type, and add list slugs or IDs to lists to collect their entries. Empty arrays disable the corresponding child streams. The objects and lists catalog streams retain all accessible metadata independently of these selections. An unknown or inaccessible configured slug or ID fails its stream visibly. Notes, tasks, and members remain workspace-wide; their readers need separate changes to narrow their coverage.
The pipeline creates its stream graph from these explicit arrays without API discovery. People and Companies have independent readers and journal progress, while both write to attio_records_raw. An object stream’s ID ends in .records.<ref> or .object_attributes.<ref>; a list stream’s ID ends in .entries.<ref> or .list_attributes.<ref>. Keep each configured reference stable: switching a slug to an equivalent UUID changes the stream ID.
Keep sourceId stable after ingestion starts. For a second workspace, use a distinct source identity and a separate table prefix or database. Copying the directory alone does not isolate pipeline IDs or destination tables.
Create tables and run the first sync
Section titled “Create tables and run the first sync”bunx chkit checkbunx chkit ingest list --tag provider:attiobunx chkit generate --name add-attiobunx chkit migrateReview the generated SQL, then apply it and run ingestion:
bunx chkit migrate --applybunx chkit ingest run --tag provider:attiobunx chkit query "SELECT count() FROM default.attio_records_raw FINAL"bunx chkit query "SELECT name, domains FROM default.attio_companies LIMIT 10"Queries in this guide use the default database and prefix. Substitute the configured names when these differ.
All synced resources and records
Section titled “All synced resources and records”Each object type has its own records and attribute streams, and each configured list has its own entries and attribute streams. Catalogs, notes, tasks, and members have workspace-wide streams. Streams for the same resource share a raw table. This table lists the returned entity data retained in raw.data; the complete API entity is preserved, including additional fields returned by Attio. Fields may be absent or null depending on the resource and workspace configuration.
| Resource | Default ClickHouse table | Records synced | API reference |
|---|---|---|---|
Objects (objects) | attio_objects_raw | Accessible standard and custom object definitions, IDs, API slug, singular and plural names, creation time | GET/objects |
Object attributes (object_attributes) | attio_object_attributes_raw | Attribute IDs, slug, title, description, type, flags, defaults, relationship definitions, configuration, creation time; includes archived definitions | GET/objects/{object_id}/attributes, GET/objects/{object_id} |
Records (records) | attio_records_raw | Independent records streams for configured object types (People and Companies by default), IDs, creation time, Attio URL, and the complete values object with all returned attribute arrays | POST/objects/{object_id}/records/query, GET/objects/{object_id} |
Lists (lists) | attio_lists_raw | List IDs, slug, name, parent objects, workspace and member access configuration, creator, creation time | GET/lists |
List attributes (list_attributes) | attio_list_attributes_raw | Attribute definitions for selected lists, including types, configuration, flags, defaults, relationships, and archived definitions | GET/lists/{list_id}/attributes, GET/lists/{list_id} |
List entries (entries) | attio_entries_raw | Entry IDs, parent object and record ID, creation time, and the complete entry_values object | POST/lists/{list_id}/entries/query, GET/lists/{list_id} |
Notes (notes) | attio_notes_raw | Note IDs, parent record links, title, plaintext and Markdown content, tags, creator, creation time, and meeting reference when returned | GET/notes |
Tasks (tasks) | attio_tasks_raw | Task IDs, plaintext content, deadline, completion state and time, linked records, assignees, creator, creation time | GET/tasks |
Workspace members (members) | attio_members_raw | Member IDs, first and last name, email address, avatar URL, access level, creation time | GET/workspace_members |
The default records streams read People and Companies separately. Deals and custom objects require explicit slugs or IDs in objects; configured types all land in the same records table. A users object, when configured, contains CRM records; workspace members are collected separately. The object catalog exposes accessible types without automatically adding readers for them.
Record and entry attributes remain arrays, including multivalued custom fields and relationship references. Returned attribute values keep their accompanying metadata. The integration does not issue separate requests for historical attribute values, select-option catalogs, or status catalogs. See the record API, entry API, and attribute API for the provider’s response shapes.
Notes retain the content and references in the notes response; a meeting reference does not fetch the meeting itself. Task links and assignees remain in the task payload. Member identity fields come from the workspace members endpoint.
API requests and pagination
Section titled “API requests and pagination”Every API path in the resource table is relative to https://api.attio.com/v2. An object/list child reader first resolves its single configured slug or ID with an individual parent request, then fetches that parent’s collection.
| Resource | Pagination and filters |
|---|---|
objects | Single collection request retaining all accessible objects |
object_attributes | limit and offset query parameters; show_archived=true |
records | limit and offset in JSON body; no record filter or custom sort |
lists | Single collection request retaining all accessible lists |
list_attributes | limit and offset query parameters; show_archived=true |
entries | limit and offset in JSON body; no entry filter or custom sort |
notes | limit and offset query parameters; no parent filter |
tasks | limit and offset query parameters; sort=created_at:asc; no completion filter |
members | Single collection request |
Paginated reads use the ingestion plugin’s paginate() helper: they start at offset zero, advance by the number of returned entities, and stop when a page is shorter than the requested limit. Each reader resolves only its configured object/list, so running People records does not depend on the objects catalog having run first. The pipeline’s stream array does not establish dependencies.
How the sync works
Section titled “How the sync works”| Behavior | Details |
|---|---|
| Sync | People, Companies, each configured custom object/list, and workspace resources have independent full-sync streams. Each reader paginates one collection through chkit-ingest; interrupted mutable offset reads replay that collection from zero. Completed and empty reads are recorded by the executor journal without a custom scan checkpoint. Custom types and lists must be configured explicitly. |
| Schedule | Run chkit ingest run through cron, CI, or an existing scheduler; the template does not start a background worker. |
| Deletions | Records absent from a later API response remain in ClickHouse. The template does not propagate deletions or consume webhooks. |
- The CLI loads the installed pipeline and selects streams by their tags.
- Each selected reader resolves its one configured object/list where needed and fetches that collection’s pages.
- The client validates the response’s
dataarray and required entity IDs. Recordvaluesand entryentry_valuesmust contain arrays. - The reader wraps each entity with its source identity and relevant parent slug, then assigns a stable composite row ID.
- The runtime batches rows and writes them to ClickHouse. The journal records execution and load progress.
- SQL views project the raw records and reconcile repeated row IDs at query time with
FINAL.
Full reads and independent recovery
Section titled “Full reads and independent recovery”Every stream uses fullSync() and begins its next execution at offset zero. Attio’s offsets describe positions in mutable collections and are not durable change cursors. A failed Companies reader therefore replays Companies independently of People; it does not maintain an outer loop over object types or a completed-parent ledger. The executor journal records execution and load completion, including successful empty reads, without custom provider checkpoint state.
Child response workspace and parent IDs are checked against the reader’s resolved object/list before rows are published. Adding a configured type creates a new stream; removing it stops future reads without removing existing rows. Every scheduled run rereads the selected collections, so edits remain observable.
Upgrading from 0.1.2 to 0.2.0 changes the former combined records, object-attributes, entries, and list-attributes stream IDs to per-type/per-list IDs. Those streams begin with fresh journal progress; the raw table schemas, row IDs for the same sourceId, and views are unchanged. Installed files are not automatically overwritten by a newer registry release.
The destination stores the latest observed entity. New observations replace earlier observations for the same row identity when ClickHouse reconciles versions. Freshness depends on the external schedule, scan duration, and successful API responses. There are no webhooks or continuous change capture in this integration.
Batching, retries, and failures
Section titled “Batching, retries, and failures”| Control | Attio integration default |
|---|---|
| Active streams, fetches, and loads | One of each per pipeline within a run |
| Destination batch threshold | 500 rows; pages are accumulated without splitting a source chunk |
| HTTP request timeout | 30 seconds |
| Delay before a request | 25 ms; 125 ms for notes |
| Source retry budget | Five retries after the initial attempt |
| Backoff | Exponential, starting at 1 second, capped at 30 seconds, with jitter |
| Retry time budget | 10 minutes per retry boundary, subject to the overall execution budget |
| Default run duration | 3600 seconds; override with --max-duration |
HTTP 429 responses honor Retry-After. Network failures and HTTP 408, 425, and 5xx responses are retried within the budget. Other 4xx responses, invalid configuration, invalid JSON, and invalid entity shapes fail without retries. Exhausting a page request’s retries fails the stream; restarting the reader does not multiply that request’s retry budget.
The request delays keep the default serial pipeline below 40 requests per second and notes below 8 requests per second, before network time. Attio can apply lower limits, including query-complexity limits; repeatedly expensive record or entry queries may require simpler filters or sorts after customization. See Attio rate limits.
Destination writes have a separate retry policy and reuse an insert deduplication token. Physical duplicate suppression depends on ClickHouse’s deduplication settings and window. The logical row identity and FINAL queries reconcile repeated observations; this is not an exactly-once delivery guarantee.
Writes become visible batch by batch. A failed or interrupted run can leave already loaded pages visible, with no rollback to the previous complete workspace snapshot. A normal stream failure allows other selected streams to be attempted. ingest run exits with 0 only when all selected streams succeed; an incomplete execution exits with 1.
Raw tables and record identity
Section titled “Raw tables and record identity”Every raw table uses the same five columns:
| Column | ClickHouse type | Meaning |
|---|---|---|
id | String | JSON-encoded composite identity for the source, resource, and entity IDs |
raw | JSON | Envelope containing source_id, optional parent slug, and the complete entity under data |
_chkit_batch_id | String | Runtime batch identity |
_chkit_run_id | String | Ingestion run identity |
_chkit_ingested_at | DateTime64(6, 'UTC') | ClickHouse publication time, populated with now64(6) |
Tables use ReplacingMergeTree(_chkit_ingested_at) with id as both the primary key and ordering key. Later ingestion time wins during replacement; the integration does not order rows by an Attio source version. Physical rows can include earlier observations until merges occur. Use FINAL when directly querying raw tables for the reconciled result.
Each ID is built as JSON.stringify([sourceId, resource, ...entityIds]). The resource names and entity ID fields are:
| Resource | Entity ID fields, in order | Extra envelope field |
|---|---|---|
objects | workspace_id, object_id | None |
object_attributes | workspace_id, object_id, attribute_id | object_slug |
records | workspace_id, object_id, record_id | object_slug |
lists | workspace_id, list_id | None |
list_attributes | workspace_id, object_id, attribute_id | list_slug |
entries | workspace_id, list_id, entry_id | list_slug |
notes | workspace_id, note_id | None |
tasks | workspace_id, task_id | None |
members | workspace_id, workspace_member_id | None |
Attio’s shared attribute response calls the parent list’s ID object_id; the list-attribute key follows that response shape. Names, email addresses, and domains are never row keys. The resource name is part of id, not an additional field in raw.
A record envelope has this shape, with illustrative IDs:
{ "source_id": "attio.primary", "object_slug": "people", "data": { "id": { "workspace_id": "workspace-id", "object_id": "people-object-id", "record_id": "person-record-id" }, "created_at": "2026-01-01T00:00:00Z", "web_url": "https://app.attio.com/example/person/person-record-id", "values": { "name": [{ "full_name": "Ada Example" }], "email_addresses": [{ "email_address": "ada@example.test" }] } }}The original entity lives under data, so custom provider fields cannot overwrite chkit’s envelope metadata. Nested arrays and fields omitted from the packaged views remain available for new SQL projections.
Included people, company, and deal views
Section titled “Included people, company, and deal views”The integration creates ordinary SQL views over attio_records_raw FINAL, filtered by object_slug. These views project the collected record rows; they do not make additional API requests.
| Derived view | Source resource | Included projection |
|---|---|---|
attio_people | records | Names, email addresses, and linked companies for people records. |
attio_companies | records | Names, domains, and descriptions for company records. |
attio_deals | records | Deal names, stages, values, currencies, and linked people and companies. |
Each view shares these columns:
| Column | Meaning |
|---|---|
id | Stable composite raw row ID |
source_id | Configured source identity |
workspace_id | Attio workspace ID |
object_id | Attio object ID |
record_id | Attio record ID |
created_at | Source creation time parsed as a nullable UTC timestamp with microsecond precision |
web_url | Record URL in Attio |
_chkit_ingested_at | Time this observation was published to ClickHouse |
The additional projections use these paths relative to raw.data.values. [1] means the first array element, following ClickHouse indexing.
| View | Column | Source value |
|---|---|---|
attio_people | name | name[1].full_name |
attio_people | email_addresses | All email_addresses[].email_address values |
attio_people | company_record_ids | All company[].target_record_id values |
attio_companies | name | name[1].value |
attio_companies | domains | All domains[].domain values |
attio_companies | description | description[1].value |
attio_deals | name | name[1].value |
attio_deals | stage | stage[1].status.title |
attio_deals | value | value[1].currency_value, parsed as Nullable(Float64) |
attio_deals | currency_code | value[1].currency_code |
attio_deals | company_record_ids | All associated_company[].target_record_id values |
attio_deals | people_record_ids | All associated_people[].target_record_id values |
Missing optional strings become empty strings; absent arrays become empty arrays. Missing or unparseable dates and amounts become null. On an initial sync without a selected deals object, the deals view is empty. Deselecting an object later leaves previously observed rows intact. Custom object records remain in the raw table and do not receive automatic typed views.
Query Attio records in ClickHouse
Section titled “Query Attio records in ClickHouse”Count the latest observed records by object:
SELECT JSONExtractString(toJSONString(raw), 'object_slug') AS object_slug, count() AS records, max(_chkit_ingested_at) AS last_observed_atFROM default.attio_records_raw FINALGROUP BY object_slugORDER BY records DESC;Aggregate deal value by stage and currency:
SELECT stage, currency_code, count() AS deals, sum(value) AS total_valueFROM default.attio_dealsGROUP BY stage, currency_codeORDER BY currency_code, total_value DESC;Grouping by currency avoids combining amounts from different currencies. The packaged amount is a floating-point projection; edit it to use a suitable decimal representation when exact monetary arithmetic is required.
Inspect list membership and retain custom entry attributes:
WITH toJSONString(raw) AS payloadSELECT JSONExtractString(payload, 'list_slug') AS list_slug, JSONExtractString(payload, 'data', 'id', 'entry_id') AS entry_id, JSONExtractString(payload, 'data', 'parent_object') AS parent_object, JSONExtractString(payload, 'data', 'parent_record_id') AS parent_record_id, JSONExtractRaw(payload, 'data', 'entry_values') AS entry_valuesFROM default.attio_entries_raw FINALLIMIT 20;Project a custom company field:
WITH toJSONString(raw) AS payloadSELECT JSONExtractString(payload, 'data', 'id', 'record_id') AS record_id, JSONExtractString(payload, 'data', 'values', 'name', 1, 'value') AS company, JSONExtractString(payload, 'data', 'values', 'customer_tier', 1, 'value') AS customer_tierFROM default.attio_records_raw FINALWHERE JSONExtractString(payload, 'object_slug') = 'companies';The last example assumes a text attribute with API slug customer_tier. Adapt the slug and value shape to the attribute definitions in attio_object_attributes_raw. Preserve source_id and workspace_id when joining records across sources, and use the provider’s record IDs for relationships.
Scheduling, verification, and recovery
Section titled “Scheduling, verification, and recovery”After the first successful run, schedule this finite command through cron, CI, or a job runner:
bunx chkit ingest run --tag provider:attio --max-duration 3600 --jsonThe scheduler supplies the project directory, credentials, runtime, cadence, and concurrency control. Run at most one ingestion process per project and ClickHouse target at a time, including runs that select different tags. Pipeline limits apply within one process and do not lock out another process.
For a narrower run, select all configured records streams:
bunx chkit ingest list --tag provider:attio --tag resource:recordsbunx chkit ingest run --tag provider:attio --tag resource:records --jsonbunx chkit ingest status --tag provider:attio --jsonRepeated tags use AND matching. Add --tag object:people to select only People records. Its record stream carries resource:records and object:people; its attribute stream carries resource:object_attributes and object:people. With the default source ID, --tag stream:attio.primary.records.people selects the People record stream. List readers carry list:<ref> together with resource:entries or resource:list_attributes.
Inspect the run’s per-stream outcomes and error messages. status reports committed execution state rather than complete run history. Keep the ingestion journal as durable operational state. After fixing a token, permission, or destination issue, rerun the affected stream; its collection starts at offset zero.
Verify a known Attio record against its retained raw.data, update that record in a test workspace, rerun the sync, and confirm its view reflects the new observation. A row count alone does not establish full API coverage. These full-sync readers ignore date bounds and do not support date-range backfills; implementing historical selection requires a source-specific strategy.
Coverage and consistency limits
Section titled “Coverage and consistency limits”| Situation | Current behavior |
|---|---|
| Source record deleted or merged | Previously observed row remains; no deletion or merge reconciliation |
| Token loses access or a parent is deselected | Existing rows remain in ClickHouse |
| Source changes during offset pagination | A scan may miss or repeat entities; it is not a provider snapshot |
| Run stops after some batches | Loaded batches remain visible; the affected stream restarts its collection at offset zero |
| Older source data loaded later | Later ingestion time wins; no source-version ordering |
| Complete change history needed | Raw tables reconcile observations and do not form a permanent change log |
| Meetings, call recordings, transcripts, emails, files, comments, or sequences needed | No readers are included for these resources |
| Historical attribute values or separate option/status catalogs needed | No separate requests are made for these resources |
| Continuous sync or OAuth lifecycle needed | Supply scheduling or authentication lifecycle outside this integration |
Deleting or deselecting a source entity does not remove it from a view. Applications requiring an exact current snapshot must add a deliberate reconciliation process. A failed or permission-limited scan must not be used as evidence that unseen source records were deleted.
Customize the installed integration
Section titled “Customize the installed integration”| File | Responsibility |
|---|---|
config.ts | Source identity, destination names, explicit object/list references, page sizes |
client.ts | Authentication, response validation, single-parent lookup, pagination, row identity, request pacing |
sources/objects.ts, sources/object-attributes.ts | Object and attribute readers with their raw table schemas |
sources/records.ts | Record reader, raw records table, people/company/deal views |
sources/lists.ts, sources/list-attributes.ts, sources/entries.ts | List resource readers with their raw table schemas |
sources/notes.ts, sources/tasks.ts, sources/members.ts | One reader and raw table schema per resource |
tests/attio.test.ts, tests/fixtures.ts | Optional installed tests and mocked API responses |
pipeline.ts | Per-type/per-list streams, resource tags, retries, batching, concurrency |
index.ts | Exports that make the pipeline and schema objects discoverable |
Remove a stream entry from pipeline.ts to stop collecting a resource. Keep its schema export to preserve existing tables under migration management. Removing a schema export changes the desired database schema and can generate a drop operation; review that migration separately.
Edit the view SQL in sources/records.ts to expose custom fields, then generate and apply a reviewed migration. Existing raw payloads support new projections without another API fetch. Reader changes apply to subsequent ingestion runs. Revisit pacing when raising concurrency, and test modified readers with fixtures before scheduling them.
Installed files belong to the project. Reinstalling does not overwrite local edits or automatically merge a newer integration version. See provider templates for version pinning and updates.
Install and run the fixture tests
Section titled “Install and run the fixture tests”Include the integration’s tests when installing it:
bunx chkit add attio --with-testsbun test src/integrations/attio/tests/attio.test.tsThe tests use fixture responses, a mocked HTTP client, and an in-memory destination. They exercise reader behavior without Attio credentials or a ClickHouse server. Edit the fixtures and assertions alongside customized readers. With --path, adjust the test command to the chosen installation directory.
Repository-only packaging and live-database tests remain outside the installed test set. The manifest selects the portable tests explicitly.
Changelog
Section titled “Changelog”Version 0.2.0
- Give People, Companies, each configured object type, and each configured list independent ingestion streams using chkit pagination.
- Make object and list selection explicit, with People and Companies enabled by default; replay interrupted mutable offset reads from the beginning of that stream.
- Preserve raw tables, scoped row identities, and typed views while changing child stream IDs; include fixtures for stream independence and failure recovery.
Version 0.1.2
- Consolidate schemas and readers into resource modules, include portable fixture tests, and document authentication, resources, views, and sync behavior.
Version 0.1.1
- Add integration guide and logo metadata; distributed source is unchanged.
Version 0.1.0
- Introduce raw CRM objects, attributes, records, lists, entries, notes, tasks, and workspace members, with People, Companies, and Deals views.
Related pages
Section titled “Related pages”- Integration list: available apps with dedicated ClickHouse integration guides.
chkit registry: discover and inspect installable apps.chkit add: installation flags, project wiring, and ownership.chkit ingest: stream selection, outcomes, and execution budgets.- Destinations and transformations: raw JSON, replacement semantics, and deletion handling.
- Scheduling and recovery: operational limits and retry behavior.
- Test a source: fixture-based checks for customized readers.