mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-07 07:55:13 +02:00
Merge origin/main into fix-uv-version-mismatch
This commit is contained in:
commit
8b2b4fa0a7
17 changed files with 1145 additions and 828 deletions
4
docs-site/app/api/search/route.ts
Normal file
4
docs-site/app/api/search/route.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import { source } from "@/lib/source";
|
||||
import { createFromSource } from "fumadocs-core/search/server";
|
||||
|
||||
export const { GET } = createFromSource(source);
|
||||
|
|
@ -69,7 +69,11 @@
|
|||
--color-fd-muted-foreground: #7a8d96;
|
||||
}
|
||||
|
||||
html, body {
|
||||
/* Keep html overflow at the default `visible` so body's overflow
|
||||
propagates to the viewport (per CSS Overflow spec). That lets
|
||||
`react-remove-scroll-bar` lock viewport scroll via body alone while
|
||||
leaving the sticky sidebar placeholder anchored to the viewport. */
|
||||
body {
|
||||
overflow-x: clip;
|
||||
}
|
||||
|
||||
|
|
@ -161,6 +165,17 @@ pre {
|
|||
line-height: 1.7 !important;
|
||||
}
|
||||
|
||||
/* Disable monospace ligatures so `--flag` keeps a visible space and double
|
||||
dashes don't fuse into an em-dash glyph. */
|
||||
code,
|
||||
pre,
|
||||
pre code,
|
||||
.ktx-code,
|
||||
.ktx-code code {
|
||||
font-variant-ligatures: none !important;
|
||||
font-feature-settings: "liga" 0, "calt" 0 !important;
|
||||
}
|
||||
|
||||
.dark pre {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
|
@ -216,57 +231,10 @@ figure[data-rehype-pretty-code-figure]:has(.ktx-code) {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── Mode A: Terminal ─────────────────────── */
|
||||
.ktx-code-terminal {
|
||||
background: #0c1417;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
color: #c8c3bc;
|
||||
box-shadow:
|
||||
0 1px 2px rgba(0, 0, 0, 0.1),
|
||||
0 12px 32px -16px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.ktx-code-terminal:hover {
|
||||
border-color: rgba(34, 211, 238, 0.2);
|
||||
box-shadow:
|
||||
0 1px 2px rgba(0, 0, 0, 0.1),
|
||||
0 14px 32px -12px rgba(34, 211, 238, 0.18);
|
||||
}
|
||||
|
||||
.ktx-code-terminal-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 10px 12px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.03), transparent);
|
||||
}
|
||||
|
||||
.ktx-tl-dot {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
border-radius: 999px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ktx-code-terminal-label {
|
||||
margin-left: 8px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.02em;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.ktx-code-body-terminal {
|
||||
background: transparent !important;
|
||||
color: #c8c3bc !important;
|
||||
}
|
||||
|
||||
/* ── Mode D: Output preview (wizard prompts, status output) ── */
|
||||
.ktx-code-output {
|
||||
background: var(--color-fd-muted);
|
||||
border: 1px solid var(--color-fd-border);
|
||||
border-left: 3px solid color-mix(in oklch, var(--color-fd-primary) 50%, var(--color-fd-border));
|
||||
position: relative;
|
||||
box-shadow: 0 1px 2px rgba(27, 27, 24, 0.02);
|
||||
}
|
||||
|
|
@ -274,17 +242,14 @@ figure[data-rehype-pretty-code-figure]:has(.ktx-code) {
|
|||
.dark .ktx-code-output {
|
||||
background: #111a1e;
|
||||
border-color: rgba(255, 255, 255, 0.05);
|
||||
border-left-color: rgba(34, 211, 238, 0.25);
|
||||
}
|
||||
|
||||
.ktx-code-output:hover {
|
||||
border-color: color-mix(in oklch, var(--color-fd-primary) 25%, var(--color-fd-border));
|
||||
border-left-color: var(--color-fd-primary);
|
||||
}
|
||||
|
||||
.dark .ktx-code-output:hover {
|
||||
border-color: rgba(255, 255, 255, 0.08);
|
||||
border-left-color: rgba(34, 211, 238, 0.45);
|
||||
}
|
||||
|
||||
.ktx-code-output-label {
|
||||
|
|
@ -304,8 +269,8 @@ figure[data-rehype-pretty-code-figure]:has(.ktx-code) {
|
|||
|
||||
.ktx-code-output-copy {
|
||||
position: absolute !important;
|
||||
top: 6px !important;
|
||||
right: 6px !important;
|
||||
top: 7px !important;
|
||||
right: 8px !important;
|
||||
opacity: 0;
|
||||
transform: translateY(-4px);
|
||||
transition: opacity 0.2s var(--ktx-ease), transform 0.2s var(--ktx-ease);
|
||||
|
|
@ -445,30 +410,10 @@ figure[data-rehype-pretty-code-figure]:has(.ktx-code) {
|
|||
border-color: rgba(34, 211, 238, 0.2);
|
||||
}
|
||||
|
||||
.ktx-code-minimal-lang {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 14px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--color-fd-muted-foreground);
|
||||
font-family: var(--font-display), var(--font-sans), sans-serif;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s var(--ktx-ease);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.ktx-code-minimal:hover .ktx-code-minimal-lang {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.ktx-code-minimal-copy {
|
||||
position: absolute !important;
|
||||
top: 6px !important;
|
||||
right: 6px !important;
|
||||
top: 7px !important;
|
||||
right: 8px !important;
|
||||
opacity: 0;
|
||||
transform: translateY(-4px);
|
||||
transition: opacity 0.2s var(--ktx-ease), transform 0.2s var(--ktx-ease);
|
||||
|
|
@ -778,8 +723,8 @@ body::after {
|
|||
mix-blend-mode: overlay;
|
||||
}
|
||||
|
||||
/* Make sure content stays above background */
|
||||
body > * {
|
||||
/* Make sure page content stays above the decorative background. */
|
||||
.ktx-site-shell {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
|
@ -1058,8 +1003,7 @@ body > * {
|
|||
.pill-badge .pill-dot { animation: none; }
|
||||
.card-lift { transition: none; }
|
||||
.ktx-code,
|
||||
.ktx-code-minimal-copy,
|
||||
.ktx-code-minimal-lang {
|
||||
.ktx-code-minimal-copy {
|
||||
transition: none;
|
||||
}
|
||||
#nd-sidebar div[data-state]:not([class]) > button[data-state] svg {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ export default function RootLayout({ children }: { children: ReactNode }) {
|
|||
suppressHydrationWarning
|
||||
>
|
||||
<body>
|
||||
<RootProvider>{children}</RootProvider>
|
||||
<RootProvider search={{ options: { api: "/ktx/api/search" } }}>
|
||||
<div className="ktx-site-shell">{children}</div>
|
||||
</RootProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ type Props = ComponentPropsWithoutRef<"pre"> & {
|
|||
"data-language"?: string;
|
||||
};
|
||||
|
||||
const TERMINAL_LANGS = new Set(["bash", "sh", "shell", "zsh"]);
|
||||
const OUTPUT_LANGS = new Set(["text", "plain", "plaintext", "console", "output"]);
|
||||
const WIZARD_GLYPHS = /^\s*[◆◇◯◐○●]/;
|
||||
|
||||
function extractText(node: ReactNode): string {
|
||||
|
|
@ -27,6 +27,33 @@ function extractText(node: ReactNode): string {
|
|||
return "";
|
||||
}
|
||||
|
||||
function findLanguageInNode(node: ReactNode): string | null {
|
||||
if (!isValidElement(node)) return null;
|
||||
const props = (node as ReactElement<{
|
||||
className?: string;
|
||||
"data-language"?: string;
|
||||
children?: ReactNode;
|
||||
}>).props;
|
||||
|
||||
const dataLang = props["data-language"];
|
||||
if (typeof dataLang === "string" && dataLang) return dataLang;
|
||||
|
||||
const className = typeof props.className === "string" ? props.className : "";
|
||||
const m = className.match(/language-([\w-]+)/);
|
||||
if (m) return m[1];
|
||||
|
||||
const children = props.children;
|
||||
if (Array.isArray(children)) {
|
||||
for (const child of children) {
|
||||
const found = findLanguageInNode(child);
|
||||
if (found) return found;
|
||||
}
|
||||
} else if (children) {
|
||||
return findLanguageInNode(children);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function detectLanguage(props: Props, children: ReactNode): string | null {
|
||||
const dataLang = props["data-language"];
|
||||
if (typeof dataLang === "string" && dataLang) return dataLang;
|
||||
|
|
@ -35,14 +62,7 @@ function detectLanguage(props: Props, children: ReactNode): string | null {
|
|||
const m = className.match(/language-([\w-]+)/);
|
||||
if (m) return m[1];
|
||||
|
||||
if (isValidElement(children)) {
|
||||
const childProps = (children as ReactElement<{ className?: string }>).props;
|
||||
const childClass = typeof childProps.className === "string" ? childProps.className : "";
|
||||
const cm = childClass.match(/language-([\w-]+)/);
|
||||
if (cm) return cm[1];
|
||||
}
|
||||
|
||||
return null;
|
||||
return findLanguageInNode(children);
|
||||
}
|
||||
|
||||
export function CodeBlock(props: Props) {
|
||||
|
|
@ -50,32 +70,11 @@ export function CodeBlock(props: Props) {
|
|||
const language = detectLanguage(props, children);
|
||||
const codeText = extractText(children);
|
||||
|
||||
const isTerminal = language !== null && TERMINAL_LANGS.has(language);
|
||||
const isOutput = !isTerminal && WIZARD_GLYPHS.test(codeText);
|
||||
const hasTitle = typeof title === "string" && title.length > 0;
|
||||
|
||||
// Mode A - Terminal (commands the user types)
|
||||
if (isTerminal) {
|
||||
return (
|
||||
<div className="not-prose ktx-code ktx-code-terminal group">
|
||||
<div className="ktx-code-terminal-head">
|
||||
<span className="ktx-tl-dot" style={{ background: "#ff5f57" }} />
|
||||
<span className="ktx-tl-dot" style={{ background: "#febc2e" }} />
|
||||
<span className="ktx-tl-dot" style={{ background: "#28c840" }} />
|
||||
<span className="ktx-code-terminal-label">
|
||||
{hasTitle ? title : "zsh"}
|
||||
</span>
|
||||
<CopyButton
|
||||
text={codeText}
|
||||
className="ml-auto text-white/80"
|
||||
/>
|
||||
</div>
|
||||
<pre {...rest} className="ktx-code-body ktx-code-body-terminal">
|
||||
{children}
|
||||
</pre>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const isOutput =
|
||||
!hasTitle &&
|
||||
(WIZARD_GLYPHS.test(codeText) ||
|
||||
(language !== null && OUTPUT_LANGS.has(language)));
|
||||
|
||||
// Mode D - Output preview (wizard prompts, terminal output)
|
||||
if (isOutput) {
|
||||
|
|
@ -110,7 +109,6 @@ export function CodeBlock(props: Props) {
|
|||
// Mode C - Minimal default
|
||||
return (
|
||||
<div className="not-prose ktx-code ktx-code-minimal group relative">
|
||||
{language && <span className="ktx-code-minimal-lang">{language}</span>}
|
||||
<CopyButton text={codeText} className="ktx-code-minimal-copy" />
|
||||
<pre {...rest} className="ktx-code-body ktx-code-body-minimal">
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -25,12 +25,12 @@ export function CopyButton({ text, className = "" }: Props) {
|
|||
type="button"
|
||||
onClick={onClick}
|
||||
aria-label={copied ? "Copied" : "Copy code"}
|
||||
className={`inline-flex items-center justify-center w-7 h-7 rounded-md transition-all hover:bg-white/5 ${className}`}
|
||||
className={`inline-flex items-center justify-center w-9 h-9 rounded-md transition-all hover:bg-fd-muted ${className}`}
|
||||
>
|
||||
{copied ? (
|
||||
<svg
|
||||
width="14"
|
||||
height="14"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
|
|
@ -44,8 +44,8 @@ export function CopyButton({ text, className = "" }: Props) {
|
|||
</svg>
|
||||
) : (
|
||||
<svg
|
||||
width="13"
|
||||
height="13"
|
||||
width="17"
|
||||
height="17"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export function DocsPageActions({ mdxSource }: Props) {
|
|||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 1500);
|
||||
} catch {
|
||||
// Clipboard denied — fail silently
|
||||
// Clipboard denied - fail silently
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -36,7 +36,7 @@ directory. Use it from any directory to generate editor or agent schema files.
|
|||
|
||||
| Flag | Description | Default |
|
||||
|------|-------------|---------|
|
||||
| `--output <file>` | Write the schema to a file instead of stdout | — |
|
||||
| `--output <file>` | Write the schema to a file instead of stdout | - |
|
||||
|
||||
## `dev runtime` Subcommands
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ connections when you use `--all`.
|
|||
| `--plain` | Print plain text output | `true` |
|
||||
| `--json` | Print JSON output | `false` |
|
||||
| `--yes` | Install required managed runtime features without prompting | `false` |
|
||||
| `--no-input` | Disable interactive terminal input | — |
|
||||
| `--no-input` | Disable interactive terminal input | - |
|
||||
|
||||
`--fast` and `--deep` are mutually exclusive. Depth flags apply only to
|
||||
database connections. Query-history flags apply only to database connections
|
||||
|
|
@ -60,7 +60,7 @@ read one item from stdin.
|
|||
| Flag | Description | Default |
|
||||
|------|-------------|---------|
|
||||
| `--text <content>` | Text content to ingest; repeat for a batch | `[]` |
|
||||
| `--connection-id <connectionId>` | Optional KTX connection id for semantic-layer capture | — |
|
||||
| `--connection-id <connectionId>` | Optional KTX connection id for semantic-layer capture | - |
|
||||
| `--user-id <id>` | Memory user id for capture attribution | `local-cli` |
|
||||
| `--json` | Print JSON output | `false` |
|
||||
| `--fail-fast` | Stop after the first failed text item | `false` |
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Introduction
|
||||
description: What KTX is, how it works, and where to start.
|
||||
description: KTX is an open-source, self-improving context layer for data agents.
|
||||
---
|
||||
|
||||
import { ProductMechanics } from "@/components/product-mechanics";
|
||||
|
|
@ -23,46 +23,67 @@ import { ProductMechanics } from "@/components/product-mechanics";
|
|||
Make analytics context usable by agents
|
||||
</h1>
|
||||
<p className="mt-4 max-w-2xl text-lg text-fd-muted-foreground" style={{ lineHeight: '1.7' }}>
|
||||
{'KTX turns warehouse metadata, semantic definitions, BI usage, and team knowledge into local files and runtime tools that database agents can trust.'}
|
||||
{'KTX is an open-source context layer for database agents. It turns warehouse metadata, BI models, query history, docs, and approved metric definitions into reviewable files agents can search and execute.'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## Why KTX
|
||||
## Why KTX helps
|
||||
|
||||
- Schemas show columns, not business rules.
|
||||
- Agents need trusted metrics, joins, filters, caveats, and provenance.
|
||||
- KTX captures that context before agents write SQL, docs, or semantic edits.
|
||||
KTX gives agents a shared context workspace before they write SQL, answer a
|
||||
question, or update analytics definitions.
|
||||
|
||||
## What KTX creates
|
||||
- **Context as code.** KTX writes wiki pages and semantic-layer definitions as
|
||||
git-based files you can review, diff, and merge.
|
||||
- **Self-improving ingest.** KTX reads warehouses, BI tools, modeling code,
|
||||
query history, and notes, then reconciles new evidence with accepted context.
|
||||
- **Executable semantics.** Agents can use approved measures, joins, filters,
|
||||
dimensions, and segments instead of rebuilding canonical SQL from scratch.
|
||||
- **Agent-native access.** CLI and MCP tools let agents search context, compile
|
||||
semantic queries, run read-only SQL, and propose updates.
|
||||
|
||||
| Path | What it gives agents |
|
||||
|------|----------------------|
|
||||
| `semantic-layer/` | Measures, dimensions, joins, grain, filters, segments |
|
||||
| `wiki/` | Business definitions, caveats, policies, analyst notes |
|
||||
| `raw-sources/` | Extracted metadata, scan output, relationship evidence |
|
||||
| `.ktx/` | Local indexes, embeddings, setup state, runtime data |
|
||||
KTX complements existing semantic layers by pairing metric definitions with the
|
||||
surrounding business knowledge, caveats, provenance, and review workflow agents
|
||||
need for data work.
|
||||
|
||||
## How KTX works
|
||||
|
||||
KTX has two connected sides: it builds and maintains the context layer, then
|
||||
serves that context to agents at runtime.
|
||||
|
||||
| Side | What KTX does |
|
||||
|------|---------------|
|
||||
| **Ingest and auto-maintain knowledge** | Reads your data stack and company knowledge, reconciles new evidence with accepted context, and keeps changes to `semantic-layer/` plus `wiki/` as version-controlled diffs automatically. |
|
||||
| **Serve agents at runtime** | Helps agents find the right wiki pages and semantic-layer entities, then compile or execute semantic queries through CLI and MCP tools. |
|
||||
|
||||
<ProductMechanics />
|
||||
|
||||
## Use it for
|
||||
|
||||
- **Generate SQL** from approved measures, dimensions, joins, and filters
|
||||
- **Explain provenance** with wiki context and warehouse evidence
|
||||
- **Repair context** through reviewable YAML and Markdown diffs
|
||||
- **Work alongside** dbt, LookML, MetricFlow, Looker, Metabase, and warehouses
|
||||
Use KTX when agents need more than raw database access. Agents can search wiki
|
||||
context, find semantic-layer entities, compile trusted semantic queries, run
|
||||
read-only SQL, and use the same tools through MCP.
|
||||
|
||||
Databases: SQLite, PostgreSQL, Snowflake, BigQuery, ClickHouse, MySQL, SQL
|
||||
Server.
|
||||
- Generate SQL from approved metrics, joins, filters, and dimensions.
|
||||
- Explain metric provenance with wiki context and source evidence.
|
||||
- Repair context through reviewable YAML and Markdown diffs.
|
||||
- Work alongside dbt, MetricFlow, LookML, Looker, Metabase, Notion, and
|
||||
supported databases.
|
||||
|
||||
## Start here
|
||||
|
||||
Choose the route that matches what you want to do next. The quickstart is the
|
||||
best first step for users; contributor setup lives in the community docs.
|
||||
|
||||
<Cards>
|
||||
<Card title="Quickstart" href="/docs/getting-started/quickstart">
|
||||
Set up KTX and build your first context in under 10 minutes.
|
||||
Install KTX, run setup, build context, and connect an agent.
|
||||
</Card>
|
||||
<Card title="Guides" href="/docs/guides/building-context">
|
||||
Hands-on workflows for scanning, ingesting, writing, and serving.
|
||||
<Card title="The Context Layer" href="/docs/concepts/the-context-layer">
|
||||
Understand why agents need more than schema access and raw SQL.
|
||||
</Card>
|
||||
<Card title="Building Context" href="/docs/guides/building-context">
|
||||
Refresh context from databases, BI tools, query history, and documents.
|
||||
</Card>
|
||||
<Card title="Writing Context" href="/docs/guides/writing-context">
|
||||
Edit semantic-layer YAML and wiki Markdown safely.
|
||||
|
|
|
|||
|
|
@ -1,135 +1,93 @@
|
|||
---
|
||||
title: Quickstart
|
||||
description: Set up KTX, build local context, and connect your coding agent.
|
||||
description: Install KTX, run setup, and connect your coding agent.
|
||||
---
|
||||
|
||||
This guide gets a local analytics project ready for KTX. You will install the
|
||||
CLI, run the setup wizard, connect a database, build context, and install agent
|
||||
rules that teach your coding assistant which KTX commands to run.
|
||||
This guide takes a local analytics project from empty to agent-ready. You'll
|
||||
install the CLI, run one guided setup command, and hand the context to a
|
||||
coding assistant.
|
||||
|
||||
If you are a coding assistant choosing a docs route, start with the
|
||||
[Agent Quickstart](/docs/ai-resources/agent-quickstart). This page is the
|
||||
human setup walkthrough.
|
||||
If you're a coding assistant choosing a docs route, start with the
|
||||
[Agent Quickstart](/docs/ai-resources/agent-quickstart) instead.
|
||||
|
||||
## What setup does
|
||||
|
||||
`ktx setup` is the main project workflow. It can create or resume `ktx.yaml`,
|
||||
configure model and embedding providers, add database connections, add optional
|
||||
context sources, build the first context artifacts, and install agent
|
||||
integration.
|
||||
|
||||
When you run bare `ktx` in an interactive terminal outside a KTX project, the
|
||||
CLI opens the same setup experience. Inside an existing project, `ktx setup`
|
||||
resumes incomplete work or opens a menu for changing setup, connecting an
|
||||
agent, checking status, or exploring a demo project.
|
||||
<div
|
||||
className="not-prose my-8 rounded-xl border border-l-4 p-5 sm:p-6"
|
||||
style={{
|
||||
borderColor: 'color-mix(in oklch, #ff8a4d 35%, transparent)',
|
||||
borderLeftColor: '#ff8a4d',
|
||||
background: 'color-mix(in oklch, #ff8a4d 8%, transparent)',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="text-xs font-semibold uppercase tracking-wider"
|
||||
style={{ color: '#ff8a4d' }}
|
||||
>
|
||||
No warehouse handy?
|
||||
</div>
|
||||
<div className="mt-2 text-base leading-relaxed text-fd-foreground">
|
||||
Try KTX against a real data stack - Postgres, dbt, Metabase, and Notion
|
||||
pre-loaded with the Orbit demo corpus. The page lists demo credentials
|
||||
you can paste straight into `ktx setup`.
|
||||
</div>
|
||||
<a
|
||||
href="https://kaelio.com/start"
|
||||
className="mt-4 inline-flex items-center gap-1 text-base font-semibold no-underline hover:underline"
|
||||
style={{
|
||||
color: '#ff8a4d',
|
||||
textDecorationColor: '#ff8a4d',
|
||||
}}
|
||||
>
|
||||
Get demo credentials at kaelio.com/start →
|
||||
</a>
|
||||
</div>
|
||||
|
||||
## Install the CLI
|
||||
|
||||
Install the published `@kaelio/ktx` package:
|
||||
Install the published package globally:
|
||||
|
||||
```bash
|
||||
npm install -g @kaelio/ktx
|
||||
```
|
||||
|
||||
Then run setup from the analytics project directory:
|
||||
KTX is open source. If you'd like to hack on it or run from a local checkout,
|
||||
the source lives at [github.com/kaelio/ktx](https://github.com/kaelio/ktx) -
|
||||
see [Contributing](/docs/community/contributing) to get set up.
|
||||
|
||||
## Run setup
|
||||
|
||||
From your project directory, run:
|
||||
|
||||
```bash
|
||||
ktx setup
|
||||
```
|
||||
|
||||
The local checkout workflow is only for KTX contributors. See
|
||||
[Contributing](/docs/community/contributing) for that path.
|
||||
The wizard walks you through everything KTX needs in one pass:
|
||||
|
||||
## Step 1: Choose the project
|
||||
1. **Project** - creates or resumes `ktx.yaml` in the current directory.
|
||||
2. **LLM** - picks a Claude backend. The default uses your local Claude Code
|
||||
session, so no API key is required. You can also use an Anthropic API key
|
||||
or Vertex AI.
|
||||
3. **Embeddings** - picks an embeddings backend. Choose OpenAI for hosted
|
||||
embeddings or `sentence-transformers` to run locally without an API key.
|
||||
4. **Database** - adds at least one primary connection. Supported drivers:
|
||||
SQLite, PostgreSQL, MySQL, ClickHouse, SQL Server, BigQuery, and Snowflake.
|
||||
5. **Context sources** - optionally adds dbt, MetricFlow, LookML, Looker,
|
||||
Metabase, or Notion. You can skip and add them later.
|
||||
6. **Build** - runs the first ingest so semantic-layer sources and wiki pages
|
||||
are ready for agents.
|
||||
7. **Agent integration** - installs project-local rules for Claude Code,
|
||||
Codex, Cursor, OpenCode, or universal `.agents`.
|
||||
|
||||
In an interactive terminal, setup can create a new KTX project or resume the
|
||||
nearest existing project. The main project file is `ktx.yaml`.
|
||||
|
||||
For scripted setup, pass the project directory explicitly:
|
||||
|
||||
```bash
|
||||
ktx setup --project-dir ./analytics
|
||||
```
|
||||
|
||||
If setup exits early, rerun `ktx setup` in the same directory. KTX keeps local
|
||||
setup progress under `.ktx/setup/` and resumes from the remaining work.
|
||||
|
||||
## Step 2: Configure the LLM
|
||||
|
||||
KTX uses a Claude model for ingest agents that turn schemas, SQL, BI metadata,
|
||||
and documents into semantic-layer sources and wiki context.
|
||||
|
||||
Setup supports three LLM provider paths:
|
||||
|
||||
| Provider | Use when | Credential model |
|
||||
|----------|----------|------------------|
|
||||
| Claude subscription (Pro/Max) | You want KTX to use your local Claude Code session | Claude Code local authentication |
|
||||
| Anthropic API key | You have an Anthropic API key | `ANTHROPIC_API_KEY` or a local `file:` secret |
|
||||
| Google Vertex AI for Anthropic Claude | Your organization runs Claude through Google Cloud | Application Default Credentials plus Vertex project and location |
|
||||
|
||||
For Anthropic API, setup can read the key from the environment or save a pasted
|
||||
key to `.ktx/secrets/anthropic-api-key`. `ktx.yaml` stores an `env:` or `file:`
|
||||
reference, not the raw key.
|
||||
|
||||
For Vertex AI, setup uses Google Application Default Credentials. It can read
|
||||
your active `gcloud` project, list visible projects, or accept explicit
|
||||
`--vertex-project` and `--vertex-location` values.
|
||||
|
||||
To use your local Claude Code session instead of an API key, set:
|
||||
|
||||
```yaml
|
||||
llm:
|
||||
provider:
|
||||
backend: claude-code
|
||||
models:
|
||||
default: sonnet
|
||||
triage: haiku
|
||||
candidateExtraction: sonnet
|
||||
curator: sonnet
|
||||
reconcile: sonnet
|
||||
repair: sonnet
|
||||
```
|
||||
|
||||
`claude-code` uses the Claude Code authentication already configured on your
|
||||
machine. It doesn't use `ANTHROPIC_API_KEY`, Vertex credentials, AI Gateway
|
||||
tokens, or Bedrock credentials. In non-interactive setup, pass
|
||||
`--llm-model opus`, `--llm-model sonnet`, `--llm-model haiku`, or a full Claude
|
||||
model ID to select the Claude Code model.
|
||||
|
||||
Setup checks the selected model before saving. Anthropic API setup fetches live
|
||||
Claude model choices when possible and falls back to bundled defaults if model
|
||||
discovery is unavailable.
|
||||
|
||||
## Step 3: Configure embeddings
|
||||
|
||||
KTX uses embeddings for semantic search over semantic-layer sources, wiki
|
||||
context, schema metadata, and relationship evidence.
|
||||
|
||||
| Backend | Default model | Notes |
|
||||
|---------|---------------|-------|
|
||||
| OpenAI | `text-embedding-3-small` | Recommended for hosted embeddings. Requires an OpenAI API key. |
|
||||
| Local sentence-transformers | `all-MiniLM-L6-v2` | Runs through the KTX-managed Python runtime. No hosted embedding key is required. |
|
||||
|
||||
OpenAI setup reads `OPENAI_API_KEY` or saves a local secret file. Local
|
||||
sentence-transformers setup can install and start the managed runtime during
|
||||
setup. To prepare that runtime before setup, run:
|
||||
If you choose local `sentence-transformers` embeddings, KTX uses the managed
|
||||
Python runtime. To prepare it before setup, run:
|
||||
|
||||
```bash
|
||||
ktx dev runtime install --feature local-embeddings --yes
|
||||
ktx dev runtime start --feature local-embeddings
|
||||
```
|
||||
|
||||
## Step 4: Add a database
|
||||
|
||||
KTX needs at least one primary database connection before it can build database
|
||||
context. The wizard supports SQLite, PostgreSQL, MySQL, ClickHouse, SQL Server,
|
||||
BigQuery, and Snowflake.
|
||||
|
||||
You can usually enter connection fields interactively or provide a URL. Secret
|
||||
URLs can be stored as local files under `.ktx/secrets/` or referenced with
|
||||
`env:NAME` in `ktx.yaml`.
|
||||
|
||||
After saving a connection, setup tests it and builds fast schema context:
|
||||
During the database step, setup tests the saved connection and builds initial
|
||||
schema context:
|
||||
|
||||
```text
|
||||
Testing warehouse
|
||||
|
|
@ -137,114 +95,24 @@ Testing warehouse
|
|||
|
||||
Building schema context for warehouse
|
||||
Running fast database ingest
|
||||
|
||||
Database ready
|
||||
warehouse - PostgreSQL - schema context complete
|
||||
```
|
||||
|
||||
PostgreSQL, BigQuery, and Snowflake can also enable query-history ingest. Query
|
||||
history helps KTX learn common query patterns, joins, service-account filters,
|
||||
and warehouse-specific usage. BigQuery and Snowflake support a lookback window;
|
||||
Postgres reads the current `pg_stat_statements` aggregate data instead.
|
||||
If setup exits early, rerun `ktx setup` in the same directory. KTX keeps
|
||||
progress under `.ktx/setup/` and resumes from the remaining work.
|
||||
|
||||
## Step 5: Add context sources
|
||||
> **Note:** Running bare `ktx` in an interactive terminal outside a KTX
|
||||
> project opens the same wizard. Inside a project, it opens a menu for
|
||||
> resuming setup, connecting an agent, checking status, or exploring a
|
||||
> pre-built demo project.
|
||||
|
||||
Context sources are optional, but they make the first context layer much richer.
|
||||
Setup can add:
|
||||
## Verify
|
||||
|
||||
| Source | Typical input | What KTX learns |
|
||||
|--------|---------------|-----------------|
|
||||
| dbt | Local project or Git repo | Models, columns, tests, descriptions, tags |
|
||||
| MetricFlow | Local project or Git repo | Semantic models, metrics, dimensions, entities |
|
||||
| LookML | Local files or Git repo | Views, explores, dimensions, measures, joins |
|
||||
| Looker | API URL and credentials | Explores, looks, dashboards, model metadata |
|
||||
| Metabase | API URL and key | Questions, dashboards, BI database mappings |
|
||||
| Notion | Integration token and crawl settings | Business docs and knowledge pages |
|
||||
|
||||
Setup maps BI and source metadata back to your primary warehouse connection so
|
||||
generated context points at the right tables.
|
||||
|
||||
You can skip this step and add sources later by rerunning `ktx setup`.
|
||||
|
||||
## Step 6: Build context
|
||||
|
||||
The context build turns configured databases and sources into local artifacts
|
||||
agents can read. It runs database ingest first, then source ingest and memory
|
||||
updates.
|
||||
|
||||
Fast database ingest records deterministic schema grounding. Deep ingest adds
|
||||
AI-enriched descriptions, embeddings, relationship evidence, and query-history
|
||||
context when configured.
|
||||
|
||||
When the build finishes, setup verifies that agent-ready context exists:
|
||||
|
||||
```text
|
||||
KTX context is ready for agents.
|
||||
|
||||
Databases:
|
||||
warehouse: deep context complete
|
||||
|
||||
Context sources:
|
||||
dbt_main: memory update complete
|
||||
|
||||
Verification:
|
||||
Agent context: ready
|
||||
Semantic search: ready
|
||||
```
|
||||
|
||||
If a foreground build is interrupted, rerun `ktx setup` or build the same target
|
||||
with `ktx ingest <connectionId>`.
|
||||
|
||||
## Step 7: Install agent integration
|
||||
|
||||
The final setup step installs project-local rules for your coding assistant.
|
||||
Supported targets are Claude Code, Codex, Cursor, OpenCode, and universal
|
||||
`.agents`.
|
||||
|
||||
You can also run this step later:
|
||||
|
||||
```bash
|
||||
ktx setup --agents --target codex
|
||||
```
|
||||
|
||||
Claude Code and Codex also support global installs:
|
||||
|
||||
```bash
|
||||
ktx setup --agents --target codex --global
|
||||
```
|
||||
|
||||
Agent rules are CLI-based. They point agents at the KTX CLI path that created
|
||||
the file, so agents do not need a separate `ktx` binary in `PATH`. If the CLI
|
||||
path changes after reinstalling or moving a checkout, rerun `ktx setup --agents`.
|
||||
|
||||
## Generated files
|
||||
|
||||
KTX writes plain files so people and agents can inspect changes in git.
|
||||
|
||||
| Path | Purpose |
|
||||
|------|---------|
|
||||
| `ktx.yaml` | Project configuration for LLMs, embeddings, connections, context sources, and query-history settings |
|
||||
| `.ktx/secrets/*` | Local secret files referenced from `ktx.yaml`; do not commit these |
|
||||
| `.ktx/setup/*` | Local setup and context-build state |
|
||||
| `.ktx/agents/install-manifest.json` | Manifest used to manage installed agent files |
|
||||
| `semantic-layer/<connection-id>/*.yaml` | Semantic source definitions used for SQL generation |
|
||||
| `wiki/global/*.md` | Shared business context and metric definitions |
|
||||
| `wiki/user/<user-id>/*.md` | User-scoped notes and local context |
|
||||
| `.claude/skills/ktx/SKILL.md` | Claude Code project skill |
|
||||
| `.agents/skills/ktx/SKILL.md` | Codex or universal project skill |
|
||||
| `.cursor/rules/ktx.mdc` | Cursor project rule |
|
||||
| `.opencode/commands/ktx.md` | OpenCode project command |
|
||||
|
||||
## Verify setup
|
||||
|
||||
Run:
|
||||
When setup finishes, check readiness:
|
||||
|
||||
```bash
|
||||
ktx status
|
||||
```
|
||||
|
||||
Example output:
|
||||
|
||||
```text
|
||||
KTX project: /home/user/analytics
|
||||
Project ready: yes
|
||||
|
|
@ -256,15 +124,49 @@ KTX context built: yes
|
|||
Agent integration ready: yes (codex:project)
|
||||
```
|
||||
|
||||
Use JSON when an agent or script needs a structured readiness check:
|
||||
For a structured check inside scripts, use `ktx status --json`.
|
||||
|
||||
```bash
|
||||
ktx status --json
|
||||
When setup builds deep context, its final context check looks like:
|
||||
|
||||
```text
|
||||
KTX context is ready for agents.
|
||||
|
||||
Databases:
|
||||
warehouse: deep context complete
|
||||
|
||||
Context sources:
|
||||
dbt_main: memory update complete
|
||||
```
|
||||
|
||||
## Scripted setup example
|
||||
## Connect a coding agent
|
||||
|
||||
Use non-interactive setup when creating repeatable fixtures or automation:
|
||||
The setup wizard installs project-local agent rules in the last step. To
|
||||
install or change targets later:
|
||||
|
||||
```bash
|
||||
ktx setup --agents
|
||||
```
|
||||
|
||||
Claude Code and Codex also support global installs with `--global`. Agent
|
||||
rules point at the KTX CLI path that created them, so agents don't need a
|
||||
separate `ktx` binary on `PATH`. If the CLI path changes, rerun
|
||||
`ktx setup --agents`.
|
||||
|
||||
## What setup writes
|
||||
|
||||
KTX writes plain files so people and agents can review changes in git.
|
||||
|
||||
| Path | Purpose |
|
||||
|------|---------|
|
||||
| `ktx.yaml` | Project configuration |
|
||||
| `.ktx/secrets/*` | Local secret files referenced from `ktx.yaml` - do not commit |
|
||||
| `semantic-layer/<connection-id>/*.yaml` | Semantic sources for SQL generation |
|
||||
| `wiki/global/*.md` | Shared business context and metric definitions |
|
||||
| `.claude/skills/ktx/`, `.agents/skills/ktx/`, `.cursor/rules/ktx.mdc`, `.opencode/commands/ktx.md` | Installed agent rules |
|
||||
|
||||
## Scripted setup
|
||||
|
||||
For repeatable fixtures and automation, skip prompts with flags:
|
||||
|
||||
```bash
|
||||
ktx setup \
|
||||
|
|
@ -287,23 +189,21 @@ ktx ingest warehouse --fast
|
|||
See [ktx setup](/docs/cli-reference/ktx-setup) for the full automation flag
|
||||
surface.
|
||||
|
||||
## Common errors
|
||||
## Common issues
|
||||
|
||||
| Symptom | Likely cause | Recovery |
|
||||
|---------|--------------|----------|
|
||||
| `ktx: command not found` | The global package is not installed or your shell cannot find it | Reinstall `@kaelio/ktx` and open a new shell |
|
||||
| Setup resumes the wrong project | `KTX_PROJECT_DIR` or the nearest `ktx.yaml` points somewhere else | Pass `--project-dir <path>` |
|
||||
| Anthropic health check fails | API key, model id, or access is invalid | Fix `ANTHROPIC_API_KEY` or rerun setup with a different key or model |
|
||||
| Vertex AI health check fails | Vertex API, Claude access, project, location, or IAM permissions are missing | Check the project, location, Application Default Credentials, and Vertex AI permissions |
|
||||
| OpenAI embeddings fail | `OPENAI_API_KEY` is missing or invalid | Export the key or choose local sentence-transformers embeddings |
|
||||
| Local embeddings fail | Managed Python runtime cannot install or start | Run `ktx dev runtime status`, then install the local embeddings runtime |
|
||||
| Database test fails | Credentials, network access, database, warehouse, or schema is wrong | Test the same values with the database's native client, then rerun setup |
|
||||
| Context is not built | Setup saved configuration but skipped or interrupted the build | Run `ktx setup` or `ktx ingest --all` |
|
||||
| Agent integration is incomplete | Setup skipped the agents step or installed a different target | Run `ktx setup --agents --target <target>` |
|
||||
| Symptom | Fix |
|
||||
|---------|-----|
|
||||
| `ktx: command not found` | Reinstall `@kaelio/ktx` and open a new shell |
|
||||
| Setup resumes the wrong project | Pass `--project-dir <path>` |
|
||||
| LLM or embeddings health check fails | Rerun setup and pick a different credential, model, or backend |
|
||||
| Database test fails | Verify the same connection with the database's native client, then rerun setup |
|
||||
| Agent integration is incomplete | Run `ktx setup --agents --target <target>` |
|
||||
|
||||
## Next steps
|
||||
|
||||
- Build and refresh context with [Building Context](/docs/guides/building-context).
|
||||
- Edit semantic sources and wiki pages with [Writing Context](/docs/guides/writing-context).
|
||||
- Refresh context with [Building Context](/docs/guides/building-context).
|
||||
- Edit semantic sources and wiki pages with
|
||||
[Writing Context](/docs/guides/writing-context).
|
||||
- Connect more tools with [Agent Clients](/docs/integrations/agent-clients).
|
||||
- Read [The Context Layer](/docs/concepts/the-context-layer) to understand the architecture.
|
||||
- Read [The Context Layer](/docs/concepts/the-context-layer) to understand
|
||||
the architecture.
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
"test": "node --test tests/*.test.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@xyflow/react": "^12.10.2",
|
||||
"fumadocs-core": "16.8.10",
|
||||
"fumadocs-mdx": "15.0.4",
|
||||
"fumadocs-ui": "16.8.10",
|
||||
|
|
@ -18,11 +19,11 @@
|
|||
"react-dom": "19.2.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@types/node": "^25.7.0",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"typescript": "^6.0",
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"tailwindcss": "^4"
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^6.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,5 +5,13 @@ export const docs = defineDocs({
|
|||
});
|
||||
|
||||
export default defineConfig({
|
||||
mdxOptions: {},
|
||||
mdxOptions: {
|
||||
rehypeCodeOptions: {
|
||||
addLanguageClass: true,
|
||||
themes: {
|
||||
light: "min-light",
|
||||
dark: "github-dark",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -111,3 +111,21 @@ test("/ktx/docs redirects to the docs introduction", async () => {
|
|||
`${docsBasePath}/docs/getting-started/introduction`,
|
||||
);
|
||||
});
|
||||
|
||||
test("/ktx/api/search returns docs search results", async () => {
|
||||
const response = await fetch(
|
||||
`${docsSiteUrl}${docsBasePath}/api/search?query=setup`,
|
||||
);
|
||||
|
||||
assert.equal(response.status, 200);
|
||||
|
||||
const results = await response.json();
|
||||
assert.ok(Array.isArray(results), "search response should be an array");
|
||||
assert.ok(
|
||||
results.some(
|
||||
(result) =>
|
||||
typeof result.url === "string" && result.url.startsWith("/docs/"),
|
||||
),
|
||||
"search should return at least one docs result",
|
||||
);
|
||||
});
|
||||
|
|
|
|||
53
docs-site/tests/docs-search-behavior.test.mjs
Normal file
53
docs-site/tests/docs-search-behavior.test.mjs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { dirname, join } from "node:path";
|
||||
import { test } from "node:test";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const docsSiteDir = join(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
|
||||
async function readDocsFile(path) {
|
||||
return readFile(join(docsSiteDir, path), "utf8");
|
||||
}
|
||||
|
||||
test("root provider uses the base-path-aware search API", async () => {
|
||||
const layout = await readDocsFile("app/layout.tsx");
|
||||
|
||||
assert.match(layout, /search=\{\{/);
|
||||
assert.match(layout, /api:\s*"\/ktx\/api\/search"/);
|
||||
});
|
||||
|
||||
test("site background stacking does not target every body child", async () => {
|
||||
const css = await readDocsFile("app/global.css");
|
||||
|
||||
assert.doesNotMatch(css, /body\s*>\s*\*\s*\{[^}]*z-index/s);
|
||||
assert.match(css, /\.ktx-site-shell\s*\{[^}]*z-index:\s*2/s);
|
||||
});
|
||||
|
||||
test("search lock relies on body overflow propagation, not html or sidebar overrides", async () => {
|
||||
const css = await readDocsFile("app/global.css");
|
||||
|
||||
// Body still clips horizontal overflow defensively.
|
||||
assert.match(css, /(^|\s)body\s*\{[^}]*overflow-x:\s*clip/s);
|
||||
|
||||
// html must keep its default `visible` overflow so body's lock
|
||||
// (`overflow: hidden` from react-remove-scroll-bar) propagates to the
|
||||
// viewport. Locking html directly breaks `position: sticky` on the
|
||||
// sidebar placeholder.
|
||||
assert.doesNotMatch(css, /(^|\s)html\s*,?\s*\{[^}]*overflow(-y|\s*:)\s*(hidden|clip)/s);
|
||||
assert.doesNotMatch(
|
||||
css,
|
||||
/html:has\(body\[data-scroll-locked\]\)[^{]*\{[^}]*overflow:\s*(hidden|clip)/s,
|
||||
);
|
||||
|
||||
// No site-specific overrides to body's data-scroll-locked overflow or
|
||||
// to the sidebar placeholder when locked.
|
||||
assert.doesNotMatch(
|
||||
css,
|
||||
/html\s+body\[data-scroll-locked\][^{]*\{[^}]*overflow:/s,
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
css,
|
||||
/body\[data-scroll-locked\]\s+\[data-sidebar-placeholder\][^{]*\{[^}]*position:\s*fixed/s,
|
||||
);
|
||||
});
|
||||
|
|
@ -23,7 +23,7 @@ test("docs introduction frames the concept before showing product mechanics", as
|
|||
|
||||
const heroIndex = introduction.indexOf("Make analytics context");
|
||||
const whyIndex = introduction.indexOf("## Why KTX");
|
||||
const createsIndex = introduction.indexOf("## What KTX creates");
|
||||
const worksIndex = introduction.indexOf("## How KTX works");
|
||||
const mechanicsIndex = introduction.indexOf("<ProductMechanics />");
|
||||
const useCaseIndex = introduction.indexOf("## Use it for");
|
||||
const heroSource = introduction.slice(0, mechanicsIndex);
|
||||
|
|
@ -34,12 +34,12 @@ test("docs introduction frames the concept before showing product mechanics", as
|
|||
"problem framing should appear after the hero",
|
||||
);
|
||||
assert.ok(
|
||||
createsIndex > whyIndex,
|
||||
"artifact summary should appear after problem framing",
|
||||
worksIndex > whyIndex,
|
||||
"mechanics bridge should appear after problem framing",
|
||||
);
|
||||
assert.ok(
|
||||
mechanicsIndex > createsIndex,
|
||||
"mechanics component should appear after the artifact summary",
|
||||
mechanicsIndex > worksIndex,
|
||||
"mechanics component should appear after the mechanics bridge",
|
||||
);
|
||||
assert.ok(
|
||||
mechanicsIndex < useCaseIndex,
|
||||
|
|
@ -49,49 +49,47 @@ test("docs introduction frames the concept before showing product mechanics", as
|
|||
assert.doesNotMatch(heroSource, /The Context Layer/);
|
||||
assert.doesNotMatch(heroSource, /Building Context/);
|
||||
assert.doesNotMatch(heroSource, /flex flex-wrap gap-3/);
|
||||
assert.doesNotMatch(introduction, /raw-sources/);
|
||||
assert.doesNotMatch(introduction, /\.ktx/);
|
||||
});
|
||||
|
||||
test("product mechanics component covers source-specific context and SQL expansion", async () => {
|
||||
test("product mechanics component explains ingestion outputs", async () => {
|
||||
const component = await readDocsFile("components/product-mechanics.tsx");
|
||||
|
||||
for (const expectedText of [
|
||||
"How KTX works",
|
||||
"Build context from source evidence",
|
||||
"Run agent requests through the model",
|
||||
"Ingestion",
|
||||
"Runtime",
|
||||
"wiki/",
|
||||
"semantic-layer/",
|
||||
"raw-sources/",
|
||||
".ktx/",
|
||||
"sl_refs",
|
||||
"Database structure",
|
||||
"BI and usage evidence",
|
||||
"Semantic modeling",
|
||||
"Company documentation",
|
||||
"Notion pages",
|
||||
"Sources",
|
||||
"KTX transforms evidence",
|
||||
"KTX builds the model",
|
||||
"Outputs KTX writes",
|
||||
"Postgres",
|
||||
"How ingestion works",
|
||||
"Ingestion flow",
|
||||
"From scattered source systems to agent-ready context",
|
||||
"wiki/*.md",
|
||||
"semantic-layer/*.yaml",
|
||||
"Wiki",
|
||||
"Semantic layer",
|
||||
"Databases",
|
||||
"BI tools",
|
||||
"Modeling code",
|
||||
"Docs and notes",
|
||||
"Source adapters",
|
||||
"Context builder",
|
||||
"Reconciliation",
|
||||
"Validation",
|
||||
"PostgreSQL",
|
||||
"Snowflake",
|
||||
"BigQuery",
|
||||
"and many others",
|
||||
"Metabase",
|
||||
"Looker",
|
||||
"dbt",
|
||||
"MetricFlow",
|
||||
"LookML",
|
||||
"extract evidence",
|
||||
"reconcile entities",
|
||||
"validate references",
|
||||
"semantic query plan",
|
||||
"dialect SQL",
|
||||
"bounded rows",
|
||||
"provenance",
|
||||
"measure: orders.total_revenue",
|
||||
"dimension: customers.segment",
|
||||
"select",
|
||||
"Notion",
|
||||
"Any text",
|
||||
"compile into SQL",
|
||||
'"use client"',
|
||||
"@xyflow/react",
|
||||
"<ReactFlow",
|
||||
"getSmoothStepPath",
|
||||
"animateMotion",
|
||||
"mechanics-particle",
|
||||
"buildParticlePath",
|
||||
]) {
|
||||
assert.ok(
|
||||
component.includes(expectedText),
|
||||
|
|
@ -99,7 +97,27 @@ test("product mechanics component covers source-specific context and SQL expansi
|
|||
);
|
||||
}
|
||||
|
||||
assert.match(
|
||||
component,
|
||||
/nodesDraggable=\{false\}/,
|
||||
"ReactFlow canvas should disable node dragging",
|
||||
);
|
||||
assert.match(
|
||||
component,
|
||||
/panOnDrag=\{false\}/,
|
||||
"ReactFlow canvas should disable panning",
|
||||
);
|
||||
assert.match(
|
||||
component,
|
||||
/zoomOnScroll=\{false\}/,
|
||||
"ReactFlow canvas should disable scroll zoom",
|
||||
);
|
||||
|
||||
assert.doesNotMatch(component, /raw-sources/);
|
||||
assert.doesNotMatch(component, /\.ktx/);
|
||||
assert.doesNotMatch(component, /Product mechanics/);
|
||||
assert.doesNotMatch(component, /How KTX works/);
|
||||
assert.doesNotMatch(component, /Runtime/);
|
||||
assert.doesNotMatch(component, /A semantic compiler for analytics agents/);
|
||||
assert.doesNotMatch(component, /KTX does more than retrieve Markdown/);
|
||||
assert.doesNotMatch(component, /Plain Markdown \+ RAG/);
|
||||
|
|
@ -109,12 +127,9 @@ test("product mechanics component covers source-specific context and SQL expansi
|
|||
assert.doesNotMatch(component, /KTX works in two moments/);
|
||||
assert.doesNotMatch(component, /name: "Metabase and query history"/);
|
||||
assert.doesNotMatch(component, /name: "dbt, MetricFlow, LookML"/);
|
||||
assert.doesNotMatch(component, /query history/);
|
||||
assert.doesNotMatch(component, /analyst notes/);
|
||||
assert.doesNotMatch(component, /ClickHouse/);
|
||||
assert.doesNotMatch(component, /MySQL/);
|
||||
assert.doesNotMatch(component, /SQL Server/);
|
||||
assert.doesNotMatch(component, /SQLite/);
|
||||
assert.doesNotMatch(
|
||||
component,
|
||||
/\/ktx\/brand\/(?:postgresql|snowflake|bigquery|clickhouse|mysql|sqlserver|sqlite|metabase|dbt|looker|notion)\.svg/,
|
||||
|
|
|
|||
184
pnpm-lock.yaml
generated
184
pnpm-lock.yaml
generated
|
|
@ -57,6 +57,9 @@ importers:
|
|||
|
||||
docs-site:
|
||||
dependencies:
|
||||
'@xyflow/react':
|
||||
specifier: ^12.10.2
|
||||
version: 12.10.2(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||
fumadocs-core:
|
||||
specifier: 16.8.10
|
||||
version: 16.8.10(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.14)(lucide-react@1.14.0(react@19.2.6))(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@4.4.3)
|
||||
|
|
@ -2748,6 +2751,24 @@ packages:
|
|||
'@types/chai@5.2.3':
|
||||
resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
|
||||
|
||||
'@types/d3-color@3.1.3':
|
||||
resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==}
|
||||
|
||||
'@types/d3-drag@3.0.7':
|
||||
resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==}
|
||||
|
||||
'@types/d3-interpolate@3.0.4':
|
||||
resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==}
|
||||
|
||||
'@types/d3-selection@3.0.11':
|
||||
resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==}
|
||||
|
||||
'@types/d3-transition@3.0.9':
|
||||
resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==}
|
||||
|
||||
'@types/d3-zoom@3.0.8':
|
||||
resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==}
|
||||
|
||||
'@types/debug@4.1.13':
|
||||
resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==}
|
||||
|
||||
|
|
@ -2853,6 +2874,15 @@ packages:
|
|||
'@vitest/utils@4.1.6':
|
||||
resolution: {integrity: sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==}
|
||||
|
||||
'@xyflow/react@12.10.2':
|
||||
resolution: {integrity: sha512-CgIi6HwlcHXwlkTpr0fxLv/0sRVNZ8IdwKLzzeCscaYBwpvfcH1QFOCeaTCuEn1FQEs/B8CjnTSjhs8udgmBgQ==}
|
||||
peerDependencies:
|
||||
react: '>=17'
|
||||
react-dom: '>=17'
|
||||
|
||||
'@xyflow/system@0.0.76':
|
||||
resolution: {integrity: sha512-hvwvnRS1B3REwVDlWexsq7YQaPZeG3/mKo1jv38UmnpWmxihp14bW6VtEOuHEwJX2FvzFw8k77LyKSk/wiZVNA==}
|
||||
|
||||
abort-controller@3.0.0:
|
||||
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
|
||||
engines: {node: '>=6.5'}
|
||||
|
|
@ -3139,6 +3169,9 @@ packages:
|
|||
class-variance-authority@0.7.1:
|
||||
resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==}
|
||||
|
||||
classcat@5.0.5:
|
||||
resolution: {integrity: sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==}
|
||||
|
||||
clean-stack@2.2.0:
|
||||
resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
|
||||
engines: {node: '>=6'}
|
||||
|
|
@ -3325,6 +3358,44 @@ packages:
|
|||
csstype@3.2.3:
|
||||
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
||||
|
||||
d3-color@3.1.0:
|
||||
resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-dispatch@3.0.1:
|
||||
resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-drag@3.0.0:
|
||||
resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-ease@3.0.1:
|
||||
resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-interpolate@3.0.1:
|
||||
resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-selection@3.0.0:
|
||||
resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-timer@3.0.1:
|
||||
resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-transition@3.0.1:
|
||||
resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==}
|
||||
engines: {node: '>=12'}
|
||||
peerDependencies:
|
||||
d3-selection: 2 - 3
|
||||
|
||||
d3-zoom@3.0.0:
|
||||
resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
data-uri-to-buffer@4.0.1:
|
||||
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
|
||||
engines: {node: '>= 12'}
|
||||
|
|
@ -5937,6 +6008,11 @@ packages:
|
|||
'@types/react':
|
||||
optional: true
|
||||
|
||||
use-sync-external-store@1.6.0:
|
||||
resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
||||
|
|
@ -6158,6 +6234,21 @@ packages:
|
|||
zod@4.4.3:
|
||||
resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==}
|
||||
|
||||
zustand@4.5.7:
|
||||
resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==}
|
||||
engines: {node: '>=12.7.0'}
|
||||
peerDependencies:
|
||||
'@types/react': '>=16.8'
|
||||
immer: '>=9.0.6'
|
||||
react: '>=16.8'
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
immer:
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
|
||||
zwitch@2.0.4:
|
||||
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
||||
|
||||
|
|
@ -9061,6 +9152,27 @@ snapshots:
|
|||
'@types/deep-eql': 4.0.2
|
||||
assertion-error: 2.0.1
|
||||
|
||||
'@types/d3-color@3.1.3': {}
|
||||
|
||||
'@types/d3-drag@3.0.7':
|
||||
dependencies:
|
||||
'@types/d3-selection': 3.0.11
|
||||
|
||||
'@types/d3-interpolate@3.0.4':
|
||||
dependencies:
|
||||
'@types/d3-color': 3.1.3
|
||||
|
||||
'@types/d3-selection@3.0.11': {}
|
||||
|
||||
'@types/d3-transition@3.0.9':
|
||||
dependencies:
|
||||
'@types/d3-selection': 3.0.11
|
||||
|
||||
'@types/d3-zoom@3.0.8':
|
||||
dependencies:
|
||||
'@types/d3-interpolate': 3.0.4
|
||||
'@types/d3-selection': 3.0.11
|
||||
|
||||
'@types/debug@4.1.13':
|
||||
dependencies:
|
||||
'@types/ms': 2.1.0
|
||||
|
|
@ -9191,6 +9303,29 @@ snapshots:
|
|||
convert-source-map: 2.0.0
|
||||
tinyrainbow: 3.1.0
|
||||
|
||||
'@xyflow/react@12.10.2(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
|
||||
dependencies:
|
||||
'@xyflow/system': 0.0.76
|
||||
classcat: 5.0.5
|
||||
react: 19.2.6
|
||||
react-dom: 19.2.6(react@19.2.6)
|
||||
zustand: 4.5.7(@types/react@19.2.14)(react@19.2.6)
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
- immer
|
||||
|
||||
'@xyflow/system@0.0.76':
|
||||
dependencies:
|
||||
'@types/d3-drag': 3.0.7
|
||||
'@types/d3-interpolate': 3.0.4
|
||||
'@types/d3-selection': 3.0.11
|
||||
'@types/d3-transition': 3.0.9
|
||||
'@types/d3-zoom': 3.0.8
|
||||
d3-drag: 3.0.0
|
||||
d3-interpolate: 3.0.1
|
||||
d3-selection: 3.0.0
|
||||
d3-zoom: 3.0.0
|
||||
|
||||
abort-controller@3.0.0:
|
||||
dependencies:
|
||||
event-target-shim: 5.0.1
|
||||
|
|
@ -9459,6 +9594,8 @@ snapshots:
|
|||
dependencies:
|
||||
clsx: 2.1.1
|
||||
|
||||
classcat@5.0.5: {}
|
||||
|
||||
clean-stack@2.2.0: {}
|
||||
|
||||
clean-stack@5.3.0:
|
||||
|
|
@ -9631,6 +9768,42 @@ snapshots:
|
|||
|
||||
csstype@3.2.3: {}
|
||||
|
||||
d3-color@3.1.0: {}
|
||||
|
||||
d3-dispatch@3.0.1: {}
|
||||
|
||||
d3-drag@3.0.0:
|
||||
dependencies:
|
||||
d3-dispatch: 3.0.1
|
||||
d3-selection: 3.0.0
|
||||
|
||||
d3-ease@3.0.1: {}
|
||||
|
||||
d3-interpolate@3.0.1:
|
||||
dependencies:
|
||||
d3-color: 3.1.0
|
||||
|
||||
d3-selection@3.0.0: {}
|
||||
|
||||
d3-timer@3.0.1: {}
|
||||
|
||||
d3-transition@3.0.1(d3-selection@3.0.0):
|
||||
dependencies:
|
||||
d3-color: 3.1.0
|
||||
d3-dispatch: 3.0.1
|
||||
d3-ease: 3.0.1
|
||||
d3-interpolate: 3.0.1
|
||||
d3-selection: 3.0.0
|
||||
d3-timer: 3.0.1
|
||||
|
||||
d3-zoom@3.0.0:
|
||||
dependencies:
|
||||
d3-dispatch: 3.0.1
|
||||
d3-drag: 3.0.0
|
||||
d3-interpolate: 3.0.1
|
||||
d3-selection: 3.0.0
|
||||
d3-transition: 3.0.1(d3-selection@3.0.0)
|
||||
|
||||
data-uri-to-buffer@4.0.1: {}
|
||||
|
||||
debug@4.4.3:
|
||||
|
|
@ -12730,6 +12903,10 @@ snapshots:
|
|||
optionalDependencies:
|
||||
'@types/react': 19.2.14
|
||||
|
||||
use-sync-external-store@1.6.0(react@19.2.6):
|
||||
dependencies:
|
||||
react: 19.2.6
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
validate-npm-package-license@3.0.4:
|
||||
|
|
@ -12907,4 +13084,11 @@ snapshots:
|
|||
|
||||
zod@4.4.3: {}
|
||||
|
||||
zustand@4.5.7(@types/react@19.2.14)(react@19.2.6):
|
||||
dependencies:
|
||||
use-sync-external-store: 1.6.0(react@19.2.6)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.14
|
||||
react: 19.2.6
|
||||
|
||||
zwitch@2.0.4: {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue