diff --git a/README.md b/README.md index 8a08e62d..d4e9c5d9 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ SQLite. Install the CLI and run the setup wizard: ```bash +npm install @kaelio/ktx npm install -g @kaelio/ktx ktx setup ``` @@ -70,6 +71,40 @@ KTX context built: yes Agent integration ready: yes (claude-code:project) ``` +Run the packaged demo without installing globally: + +```bash +npx @kaelio/ktx setup demo --no-input +npx @kaelio/ktx setup demo inspect +``` + +The default demo uses packaged sample data and prebuilt context. It does not +require API keys, network access, or an LLM provider. + +Generate SQL from a semantic-layer source: + +```bash +npx @kaelio/ktx sl query --project-dir "$PROJECT_DIR" \ + --connection-id warehouse \ + --measure accounts.account_count \ + --dimension accounts.segment \ + --format sql +``` + +List and test a configured warehouse connection: + +```bash +ktx connection list --project-dir "$PROJECT_DIR" +ktx connection test warehouse --project-dir "$PROJECT_DIR" +``` + +The connection test prints the configured driver and discovered table count: + +```text +Driver: sqlite +Tables: 1 +``` + ## What's in a project ``` @@ -97,6 +132,47 @@ Semantic sources and knowledge pages are committed to git. The `.ktx/` directory holds ephemeral state and is git-ignored — delete it and KTX rebuilds on the next run. +### Scan the demo warehouse + +Scan artifacts are written under +`raw-sources/warehouse/live-database//` in the project directory. + +```bash +SCAN_OUTPUT="$(ktx scan warehouse --project-dir "$PROJECT_DIR")" +printf '%s\n' "$SCAN_OUTPUT" +SCAN_RUN_ID="$(printf '%s\n' "$SCAN_OUTPUT" | awk '/^Run: / { print $2 }')" +ktx scan status --project-dir "$PROJECT_DIR" "$SCAN_RUN_ID" +ktx scan report --project-dir "$PROJECT_DIR" "$SCAN_RUN_ID" +``` + +For non-SQLite drivers, prefer credential references such as `--url env:NAME` +or `--url file:PATH` over literal credential URLs. + +## Managed Python runtime + +KTX installs its Python runtime only when a Python-backed command needs it. +The runtime lives outside the npm cache, is versioned by the installed CLI +version, and is managed by `ktx runtime` commands. + +KTX requires `uv` on `PATH` to create the managed runtime. Install `uv` with +your system package manager or the official installer before running Python- +backed KTX commands. KTX doesn't download `uv` automatically; run +`ktx runtime doctor` if runtime installation fails: + +```bash +ktx runtime install --yes +ktx runtime status +ktx runtime doctor +ktx runtime start +ktx runtime stop +ktx runtime prune --dry-run +ktx runtime prune --yes +``` + +The release artifact manifest contains the public npm tarball and the bundled `kaelio-ktx` +runtime wheel. The `python/ktx-sl` and `python/ktx-daemon` directories remain +source packages for development, not public release artifacts. + ## Serve agents KTX integrates with coding agents through CLI skills, an MCP server, or both. @@ -126,6 +202,11 @@ This exposes tools for connections, knowledge search, semantic-layer sources, validation, queries, ingestion, and replay. The `--semantic-compute` flag starts the managed Python runtime for query planning automatically. +The standalone MCP server exposes `connection_list`, `knowledge_search`, +`knowledge_read`, `knowledge_write`, `sl_list_sources`, `sl_read_source`, +`sl_write_source`, `sl_validate`, `sl_query`, `ingest_trigger`, +`ingest_status`, `ingest_report`, and `ingest_replay`. + Supported agents: Claude Code, Codex, Cursor, OpenCode, and any agent that reads `.agents/` skills or MCP configuration. @@ -136,7 +217,13 @@ reads `.agents/` skills or MCP configuration. | `packages/cli` | CLI entry point | | `packages/context` | Core context engine | | `packages/llm` | LLM and embedding providers | -| `packages/connector-*` | Database connectors (Postgres, Snowflake, BigQuery, ClickHouse, MySQL, SQL Server, SQLite) | +| `packages/connector-bigquery` | BigQuery scan connector | +| `packages/connector-clickhouse` | ClickHouse scan connector | +| `packages/connector-mysql` | MySQL scan connector | +| `packages/connector-postgres` | Postgres scan connector | +| `packages/connector-snowflake` | Snowflake scan connector | +| `packages/connector-sqlite` | SQLite scan connector | +| `packages/connector-sqlserver` | SQL Server scan connector | | `python/ktx-sl` | Semantic-layer query planning | | `python/ktx-daemon` | Portable compute service | diff --git a/packages/cli/assets/demo/orbit/knowledge/global/new-hire-onboarding-policy.md b/packages/cli/assets/demo/orbit/knowledge/global/new-hire-onboarding-policy.md index 5e827355..2059329d 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/new-hire-onboarding-policy.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/new-hire-onboarding-policy.md @@ -12,7 +12,7 @@ refs: ## New Hire Week-One Onboarding Policy -**Source:** Notion — People & Operating Norms, last edited 2026-05-07 +**Source:** Notion — People & Operating Norms, last edited 2026-05-07 **Owner:** Manager (not People Ops) --- diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-activation-kpi-glossary.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-activation-kpi-glossary.md index 7998c35a..dc97bdc2 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-activation-kpi-glossary.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-activation-kpi-glossary.md @@ -20,7 +20,7 @@ tables: # Activation KPI Glossary -**Owner team:** Growth +**Owner team:** Growth **Source:** Notion — Orbit Demo Home / Data Team - Onboarding / Activation KPI Glossary, last edited 2026-05-07 Use this when a question is about signup-to-habit behavior. Orbit uses activation language across Growth, Product, and CS conversations. @@ -62,4 +62,3 @@ Growth conversations typically use D7 and D14 Activation Rate. Product and CS ma ## Relationship to Account-Level Activation This glossary defines **customer-level** activation (signup-to-habit). The **account-level** activation workflow (requester login → first approved purchase request → account activated) is a separate concept tracked in `mart_account_activity` and governed by the January 2026 policy change. See `orbit-activation-policy-change-jan-2026` for that definition. - diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-activation-policy-change-jan-2026.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-activation-policy-change-jan-2026.md index 675abb63..3216d94d 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-activation-policy-change-jan-2026.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-activation-policy-change-jan-2026.md @@ -14,9 +14,9 @@ sl_refs: # Activation Policy Change — January 2026 -**Governed metric key:** `activated_accounts` -**Owner team:** growth -**Notion:** `notion://notion_page_activation_policy_decision#policy-change` +**Governed metric key:** `activated_accounts` +**Owner team:** growth +**Notion:** `notion://notion_page_activation_policy_decision#policy-change` **Sources:** `mart_account_activity`, `int_activation_policy_windows`, `stg_activation_events` ## Policy Boundary diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-arr-contract-first-definition.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-arr-contract-first-definition.md index ac8cd076..4cb34b76 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-arr-contract-first-definition.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-arr-contract-first-definition.md @@ -15,9 +15,9 @@ sl_refs: # ARR — Contract-First Definition -**Governed metric key:** `arr` -**Owner team:** finance -**Notion:** `notion://notion_page_arr_contract_reporting#arr-contract-first` +**Governed metric key:** `arr` +**Owner team:** finance +**Notion:** `notion://notion_page_arr_contract_reporting#arr-contract-first` **Source:** `mart_arr_daily` (grain: `metric_date`) ## Rule diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-company-overview.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-company-overview.md index 6cf4afac..83645aeb 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-company-overview.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-company-overview.md @@ -21,7 +21,7 @@ refs: Orbit sells procurement workflow and spend-control software. The core value proposition: route purchase requests, collect approvals, onboard suppliers, and issue purchase orders without turning every exception into a status hunt. -**Primary buyers:** Finance, Procurement, Business Operations. +**Primary buyers:** Finance, Procurement, Business Operations. **Daily users:** department admins, office managers, IT leads, legal ops partners — anyone who has to get a vendor through the building. ## Product Workflow @@ -69,4 +69,3 @@ Orbit sells procurement workflow and spend-control software. The core value prop - "Supplier onboarding is split across three teams." - "Renewals are visible too late." - "People keep asking Finance for status because there is nowhere better to look." - diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-customer-health-risk-definition.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-customer-health-risk-definition.md index 4457bd21..56deb3f3 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-customer-health-risk-definition.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-customer-health-risk-definition.md @@ -14,9 +14,9 @@ sl_refs: # Customer Health Risk Definition -**Governed metric key:** `active_customers` -**Owner team:** customer_success -**Notion:** `notion://notion_page_customer_health_playbook#risk-definition` +**Governed metric key:** `active_customers` +**Owner team:** customer_success +**Notion:** `notion://notion_page_customer_health_playbook#risk-definition` **Sources:** `mart_customer_health`, `int_customer_health_signals` ## Risk Levels diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-customers-source.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-customers-source.md index 3822e31e..e98c1663 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-customers-source.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-customers-source.md @@ -18,8 +18,8 @@ tables: # Orbit Customers Source -**Table:** `orbit_analytics.customer` -**Grain:** one row per signed-up customer +**Table:** `orbit_analytics.customer` +**Grain:** one row per signed-up customer **Source:** Notion — Orbit Demo Home / Data Team - Onboarding / Orbit Customers Source, last edited 2026-05-07 Use this when a question needs customer identity, plan tier, signup timing, recent activity, or the standard customer joins. @@ -58,4 +58,3 @@ Always join through `customer.id`. Do not join on `email`. - **Timezone:** `created_at` and `last_seen_at` are UTC. Confirm whether a question expects UTC or a local business day before filtering. - **Paying vs. all:** `free` customers must be excluded from paying-customer follow-ups. Use `paying_customer_count`, not `customer_count`. - **plan_tier values:** `free`, `pro`, `enterprise`. Note: `pro_plus` is a legacy alias for `growth` in the account/contract layer (see `orbit-plan-segment-normalization`), but `plan_tier` on this table uses `pro` not `pro_plus`. - diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-dbt-exposures.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-dbt-exposures.md index 981d494c..05011e48 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-dbt-exposures.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-dbt-exposures.md @@ -42,4 +42,3 @@ Declared in `models/exposures.yml`. All exposures are type `dashboard` with matu - **Owner:** Growth (growth@orbit-demo.example.com) - **Depends on:** `mart_account_activity` - **Description:** Activation policy comparison around the January 2026 workflow update. - diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-dbt-project-overview.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-dbt-project-overview.md index 11aac427..41179bc2 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-dbt-project-overview.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-dbt-project-overview.md @@ -22,10 +22,10 @@ sl_refs: # Orbit dbt Project Overview -**Project name:** `kaelio_demo` -**dbt version:** 1.0.0 -**Profile target:** Postgres (`orbit_analytics` schema, `kaelio_demo` database) -**Raw source schema:** `orbit_raw` +**Project name:** `kaelio_demo` +**dbt version:** 1.0.0 +**Profile target:** Postgres (`orbit_analytics` schema, `kaelio_demo` database) +**Raw source schema:** `orbit_raw` **Analytics schema:** `orbit_analytics` (all models materialised as views by default) ## Model Layers @@ -52,4 +52,3 @@ sl_refs: ## Raw Source Tables (`orbit_raw` schema) accounts, account_hierarchy, plans, contracts, subscriptions, contract_discount_terms, arr_movements, invoices, invoice_line_items, refunds, plan_segment_mapping, users, activation_events, sessions, purchase_requests, approval_events, suppliers, supplier_onboarding_events, purchase_orders, support_tickets, account_owners. - diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-account-activity.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-account-activity.md index 29ba3392..74a936f6 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-account-activity.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-account-activity.md @@ -20,7 +20,7 @@ tables: -**Table:** `orbit_analytics.mart_account_activity` +**Table:** `orbit_analytics.mart_account_activity` **Grain:** one row per `policy_change_date` ## Columns @@ -47,4 +47,3 @@ tables: - The January 2026 activation policy change (`policy_change_date = 2026-01-15`) is the primary boundary. `policy_version` in upstream events splits into `pre_2026_01_15` and `post_2026_01_15` cohorts. - Rates are ratios (0–1); multiply by 100 for percentage display. - See [orbit-activation-policy-change-jan-2026](orbit-activation-policy-change-jan-2026) for full policy context. - diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-account-segments.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-account-segments.md index d23ee684..04085359 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-account-segments.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-account-segments.md @@ -19,7 +19,7 @@ tables: -**Table:** `orbit_analytics.mart_account_segments` +**Table:** `orbit_analytics.mart_account_segments` **Grain:** one row per `account_id` ## Columns @@ -53,4 +53,3 @@ tables: - `normalized_plan_code` maps `pro_plus` → `growth`. Always use `normalized_plan_code` for plan-based reporting. See [orbit-plan-segment-normalization](orbit-plan-segment-normalization). - `segment` is derived from `canonical_plan_code × size_band` via `stg_plan_segment_mapping`. - `contract_arr_cents` is the contract-first ARR value. See [orbit-arr-contract-first-definition](orbit-arr-contract-first-definition). - diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-arr-daily.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-arr-daily.md index f1231a30..5b3db7dd 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-arr-daily.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-arr-daily.md @@ -18,7 +18,7 @@ tables: -**Table:** `orbit_analytics.mart_arr_daily` +**Table:** `orbit_analytics.mart_arr_daily` **Grain:** one row per `metric_date` ## Columns @@ -44,4 +44,3 @@ tables: - ARR is calculated contract-first: active contract ARR takes precedence over subscription ARR for any covered period. See [orbit-arr-contract-first-definition](orbit-arr-contract-first-definition). - `display` is a formatted label for UI rendering; use `arr_cents` for all arithmetic. - diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-nrr-quarterly.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-nrr-quarterly.md index 9b423e6d..288c8201 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-nrr-quarterly.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-nrr-quarterly.md @@ -20,7 +20,7 @@ tables: -**Table:** `orbit_analytics.mart_nrr_quarterly` +**Table:** `orbit_analytics.mart_nrr_quarterly` **Grain:** one row per `quarter_label` × `segment` ## Columns @@ -53,4 +53,3 @@ tables: - `net_revenue_retention` is a ratio, not a percentage. Multiply by 100 for display. - Contraction includes discount expirations (classified as contraction, not churn). See [orbit-nrr-discount-expiration-treatment](orbit-nrr-discount-expiration-treatment). - Enterprise is the primary executive reporting segment. - diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-procurement-activity.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-procurement-activity.md index 0b31edae..ab3de364 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-procurement-activity.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-procurement-activity.md @@ -18,7 +18,7 @@ tables: -**Table:** `orbit_analytics.mart_procurement_activity` +**Table:** `orbit_analytics.mart_procurement_activity` **Grain:** one row per `week_start_date` × `contract_arr_threshold_cents` ## Columns @@ -45,4 +45,3 @@ tables: - `active_requesters` counts non-internal, non-test requesters on large active contracts. See [orbit-procurement-qualifying-actions](orbit-procurement-qualifying-actions). - The standard threshold is `contract_arr_threshold_cents = 20000000` ($200k ARR). - Always filter by `contract_arr_threshold_cents` — the table contains rows for multiple threshold values. - diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-retention-movement-breakout.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-retention-movement-breakout.md index d5021f0a..7c22cf16 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-retention-movement-breakout.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-retention-movement-breakout.md @@ -19,7 +19,7 @@ tables: -**Table:** `orbit_analytics.mart_retention_movement_breakout` +**Table:** `orbit_analytics.mart_retention_movement_breakout` **Grain:** one row per `quarter_label` × `segment` × `movement_type` × `movement_reason` ## Columns @@ -53,4 +53,3 @@ tables: - Contraction includes discount expirations, classified as contraction (not churn), tracked via `movement_reason`. See [orbit-nrr-discount-expiration-treatment](orbit-nrr-discount-expiration-treatment). - This table is the row-level source for `mart_nrr_quarterly` aggregations. - Only one of `expansion_arr_cents`, `contraction_arr_cents`, `churned_arr_cents` is non-zero per row. - diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-revenue-daily.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-revenue-daily.md index 6a088de0..8deb5ffe 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-revenue-daily.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-mart-revenue-daily.md @@ -20,7 +20,7 @@ tables: -**Table:** `orbit_analytics.mart_revenue_daily` +**Table:** `orbit_analytics.mart_revenue_daily` **Grain:** one row per `revenue_date` ## Columns @@ -54,4 +54,3 @@ tables: - `reconciliation_check` must be `true` on every row. Any `false` row indicates a data quality issue. - Gross-to-net reconciliation: gross revenue − credits − refunds = net revenue. See [orbit-revenue-gross-to-net-reconciliation](orbit-revenue-gross-to-net-reconciliation). - All amounts are in cents; divide by 100 for USD, by 100,000,000 for $M. - diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-metabase-sql-library-patterns.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-metabase-sql-library-patterns.md index d94ba88b..28055b9b 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-metabase-sql-library-patterns.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-metabase-sql-library-patterns.md @@ -69,4 +69,3 @@ Card 48 is the canonical reference; card 55 is a filtered variant for large-cont | 53 | Enterprise NRR quarter breakout | mart_nrr_quarterly | 0 | | 54 | February credits drilldown | mart_revenue_daily | 0 | | 55 | Large contract requesters | mart_account_segments | 0 | - diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-nrr-discount-expiration-treatment.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-nrr-discount-expiration-treatment.md index 4af79d78..0b966d8c 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-nrr-discount-expiration-treatment.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-nrr-discount-expiration-treatment.md @@ -15,9 +15,9 @@ sl_refs: # NRR — Discount Expiration Treatment -**Governed metric key:** `net_revenue_retention` -**Owner team:** analytics -**Notion:** `notion://notion_page_retention_policy_current#nrr-definition` and `#discount-expiration-treatment` +**Governed metric key:** `net_revenue_retention` +**Owner team:** analytics +**Notion:** `notion://notion_page_retention_policy_current#nrr-definition` and `#discount-expiration-treatment` **Sources:** `mart_nrr_quarterly`, `mart_retention_movement_breakout` ## NRR Definition diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-plan-segment-normalization.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-plan-segment-normalization.md index aeab9be3..580c1fa1 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-plan-segment-normalization.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-plan-segment-normalization.md @@ -14,9 +14,9 @@ sl_refs: # Plan & Segment Normalization -**Governed metric key:** `segment` -**Owner team:** sales_ops -**Notion:** `notion://notion_page_sales_ops_segmentation#growth-plan-normalization` +**Governed metric key:** `segment` +**Owner team:** sales_ops +**Notion:** `notion://notion_page_sales_ops_segmentation#growth-plan-normalization` **Sources:** `mart_account_segments`, `stg_plan_segment_mapping`, `stg_plans` ## Canonical Plan Codes diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-procurement-qualifying-actions.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-procurement-qualifying-actions.md index 87cc64c5..08126dd5 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-procurement-qualifying-actions.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-procurement-qualifying-actions.md @@ -14,9 +14,9 @@ sl_refs: # Procurement — Qualifying Actions & Weekly Active Requesters -**Governed metric key:** `weekly_active_requesters` -**Owner team:** product -**Notion:** `notion://notion_page_procurement_instrumentation#qualifying-procurement-actions` +**Governed metric key:** `weekly_active_requesters` +**Owner team:** product +**Notion:** `notion://notion_page_procurement_instrumentation#qualifying-procurement-actions` **Sources:** `mart_procurement_activity`, `int_procurement_qualifying_actions` ## Qualifying Action Definition diff --git a/packages/cli/assets/demo/orbit/knowledge/global/orbit-revenue-gross-to-net-reconciliation.md b/packages/cli/assets/demo/orbit/knowledge/global/orbit-revenue-gross-to-net-reconciliation.md index 7de4138b..65004331 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/orbit-revenue-gross-to-net-reconciliation.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/orbit-revenue-gross-to-net-reconciliation.md @@ -14,9 +14,9 @@ sl_refs: # Revenue — Gross-to-Net Reconciliation -**Governed metric key:** `net_revenue` -**Owner team:** finance -**Notion:** `notion://notion_page_revenue_reporting_policy#gross-to-net-reconciliation` +**Governed metric key:** `net_revenue` +**Owner team:** finance +**Notion:** `notion://notion_page_revenue_reporting_policy#gross-to-net-reconciliation` **Source:** `mart_revenue_daily` (grain: `revenue_date`) ## Formula diff --git a/packages/cli/assets/demo/orbit/knowledge/global/sales-ops-cs-handoff-process.md b/packages/cli/assets/demo/orbit/knowledge/global/sales-ops-cs-handoff-process.md index 13eb139f..d547d026 100644 --- a/packages/cli/assets/demo/orbit/knowledge/global/sales-ops-cs-handoff-process.md +++ b/packages/cli/assets/demo/orbit/knowledge/global/sales-ops-cs-handoff-process.md @@ -14,7 +14,7 @@ refs: ## Sales Ops → Customer Success Implementation Handoff -**Source:** Notion — People & Operating Norms, last edited 2026-05-07 +**Source:** Notion — People & Operating Norms, last edited 2026-05-07 **Owner:** Sales Ops (sender), Customer Success (receiver) --- diff --git a/packages/cli/src/demo.test.ts b/packages/cli/src/demo.test.ts index 5c9fa7ac..0b053ee6 100644 --- a/packages/cli/src/demo.test.ts +++ b/packages/cli/src/demo.test.ts @@ -11,6 +11,9 @@ import type { renderMemoryFlowTui } from './memory-flow-tui.js'; import { KTX_NEXT_STEP_COMMANDS } from './next-steps.js'; import { resetVizFallbackWarningsForTest } from './viz-fallback.js'; +const SEEDED_DEMO_SEMANTIC_SOURCE_COUNT = 46; +const SEEDED_DEMO_KNOWLEDGE_PAGE_COUNT = 28; + function makeIo(options: { isTTY?: boolean; columns?: number; rawMode?: boolean } = {}) { let stdout = ''; let stderr = ''; @@ -336,8 +339,14 @@ describe('runKtxDemo', () => { notion: { pageCount: 8 }, }, generatedOutputs: { - semanticLayer: { manifestSourceCount: 46, fileCount: 46 }, - knowledge: { manifestPageCount: 28, fileCount: 28 }, + semanticLayer: { + manifestSourceCount: SEEDED_DEMO_SEMANTIC_SOURCE_COUNT, + fileCount: SEEDED_DEMO_SEMANTIC_SOURCE_COUNT, + }, + knowledge: { + manifestPageCount: SEEDED_DEMO_KNOWLEDGE_PAGE_COUNT, + fileCount: SEEDED_DEMO_KNOWLEDGE_PAGE_COUNT, + }, links: { manifestLinkCount: 23, linkCount: 23 }, reports: { primaryPath: 'reports/seeded-demo-report.json', fileCount: 1 }, }, @@ -636,10 +645,16 @@ describe('runKtxDemo', () => { ).resolves.toBe(0); expect(seededIo.stdout()).toContain('Status: ready'); - expect(seededIo.stdout()).toContain('Semantic-layer sources: 46 manifest, 46 files'); - expect(seededIo.stdout()).toContain('Knowledge pages: 28 manifest, 28 files'); + expect(seededIo.stdout()).toContain( + `Semantic-layer sources: ${SEEDED_DEMO_SEMANTIC_SOURCE_COUNT} manifest, ${SEEDED_DEMO_SEMANTIC_SOURCE_COUNT} files`, + ); + expect(seededIo.stdout()).toContain( + `Knowledge pages: ${SEEDED_DEMO_KNOWLEDGE_PAGE_COUNT} manifest, ${SEEDED_DEMO_KNOWLEDGE_PAGE_COUNT} files`, + ); expect(seededIo.stdout()).not.toContain('Status: corrupt'); - expect(seededIo.stdout()).not.toContain('Semantic-layer sources: 46 manifest, 0 files'); + expect(seededIo.stdout()).not.toContain( + `Semantic-layer sources: ${SEEDED_DEMO_SEMANTIC_SOURCE_COUNT} manifest, 0 files`, + ); }); it('fails corrupted demo projects in no-input mode with reset guidance', async () => { diff --git a/packages/cli/src/setup.test.ts b/packages/cli/src/setup.test.ts index cd6e9a9f..58efc506 100644 --- a/packages/cli/src/setup.test.ts +++ b/packages/cli/src/setup.test.ts @@ -3,6 +3,7 @@ import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { localFakeBundleReport, persistLocalBundleReport } from './ingest.test-utils.js'; import { contextBuildCommands, writeKtxSetupContextState } from './setup-context.js'; import { runDemoTour } from './setup-demo-tour.js'; import { readKtxSetupStatus, runKtxSetup } from './setup.js'; @@ -311,6 +312,62 @@ describe('setup status', () => { }); }); + it('reports Vertex LLM and context ready after a successful Metabase ingest report', async () => { + await writeFile( + join(tempDir, 'ktx.yaml'), + [ + 'project: revenue', + 'setup:', + ' database_connection_ids:', + ' - warehouse', + ' completed_steps:', + ' - project', + ' - databases', + ' - sources', + 'connections:', + ' warehouse:', + ' driver: postgres', + ' url: env:DATABASE_URL', + ' metabase:', + ' driver: metabase', + ' url: env:METABASE_URL', + ' api_key_ref: env:METABASE_API_KEY', + ' warehouse_connection_id: warehouse', + 'llm:', + ' provider:', + ' backend: vertex', + ' vertex:', + ' project: kaelio-dev', + ' location: us-east5', + ' models:', + ' default: claude-sonnet-4-6', + 'ingest:', + ' embeddings:', + ' backend: deterministic', + ' model: deterministic', + ' dimensions: 8', + '', + ].join('\n'), + 'utf-8', + ); + await persistLocalBundleReport( + tempDir, + localFakeBundleReport('metabase-job-1', { + connectionId: 'warehouse', + sourceKey: 'metabase', + }), + ); + + const status = await readKtxSetupStatus(tempDir); + const io = makeIo(); + await expect(runKtxSetup({ command: 'status', projectDir: tempDir, json: false }, io.io)).resolves.toBe(0); + + expect(status.llm).toMatchObject({ backend: 'vertex', ready: true, model: 'claude-sonnet-4-6' }); + expect(status.context).toMatchObject({ ready: true, status: 'completed' }); + expect(io.stdout()).toContain('LLM ready: yes (claude-sonnet-4-6)'); + expect(io.stdout()).toContain('KTX context built: yes'); + }); + it('prints plain and JSON setup status', async () => { const plainIo = makeIo(); const jsonIo = makeIo(); diff --git a/packages/cli/src/setup.ts b/packages/cli/src/setup.ts index 47a7997a..a4f081d0 100644 --- a/packages/cli/src/setup.ts +++ b/packages/cli/src/setup.ts @@ -1,7 +1,8 @@ import { existsSync } from 'node:fs'; import { join, resolve } from 'node:path'; import { cancel, isCancel, select } from '@clack/prompts'; -import { loadKtxProject } from '@ktx/context/project'; +import { getLatestLocalIngestStatus, savedMemoryCountsForReport } from '@ktx/context/ingest'; +import { ktxLocalStateDbPath, loadKtxProject, type KtxLocalProject } from '@ktx/context/project'; import type { KtxCliIo } from './cli-runtime.js'; import { formatSetupNextStepLines } from './next-steps.js'; import { isKtxSetupExitError, withSetupInterruptConfirmation } from './setup-interrupt.js'; @@ -248,6 +249,31 @@ function sourceConnections(config: Awaited>['c .sort((left, right) => left.connectionId.localeCompare(right.connectionId)); } +type LocalIngestStatusReport = NonNullable>>; + +function reportHasSavedContext(report: LocalIngestStatusReport): boolean { + if (report.body.failedWorkUnits.length > 0) { + return false; + } + const counts = savedMemoryCountsForReport(report); + return counts.wikiCount > 0 || counts.slCount > 0; +} + +async function readIngestContextStatus(project: KtxLocalProject): Promise { + if (!existsSync(ktxLocalStateDbPath(project))) { + return null; + } + const report = await getLatestLocalIngestStatus(project); + if (!report || !reportHasSavedContext(report)) { + return null; + } + return { + ready: true, + status: 'completed', + runId: report.runId, + }; +} + export async function readKtxSetupStatus(projectDir: string): Promise { const resolvedProjectDir = resolve(projectDir); if (!existsSync(join(resolvedProjectDir, 'ktx.yaml'))) { @@ -279,6 +305,10 @@ export async function readKtxSetupStatus(projectDir: string): Promise { const knowledgeSearch = structuredContent<{ results: Array<{ key: string; summary: string; score: number }>; totalFound: number; - }>(await client.callTool({ name: 'knowledge_search', arguments: { query: 'ARR contract', limit: 5 } })); + }>(await client.callTool({ name: 'knowledge_search', arguments: { query: 'ARR contract-first definition', limit: 10 } })); expect(knowledgeSearch.totalFound).toBeGreaterThan(0); expect(knowledgeSearch.results.map((result) => result.key)).toContain('orbit-arr-contract-first-definition'); @@ -387,7 +387,7 @@ describe('standalone built ktx CLI smoke', () => { const slRead = structuredContent<{ sourceName: string; yaml: string }>( await client.callTool({ name: 'sl_read_source', - arguments: { connectionId: 'postgres-warehouse', sourceName: 'mart_arr_daily' }, + arguments: { connectionId: 'dbt-main', sourceName: 'mart_arr_daily' }, }), ); expect(slRead.sourceName).toBe('mart_arr_daily'); @@ -397,7 +397,7 @@ describe('standalone built ktx CLI smoke', () => { const slValidate = structuredContent<{ success: boolean; errors: string[]; warnings: string[] }>( await client.callTool({ name: 'sl_validate', - arguments: { connectionId: 'postgres-warehouse', names: ['mart_arr_daily'] }, + arguments: { connectionId: 'dbt-main', names: ['mart_arr_daily', 'stg_contracts'] }, }), ); expect(slValidate.success).toBe(true);