Commit graph

472 commits

Author SHA1 Message Date
Andrey Avtomonov
470802e58e
fix(cli): classify ktx setup abandonment as aborted, not a blank error (#278)
* fix(cli): classify ktx setup abandonment as aborted, not a blank error

ktx setup returned a non-zero exit code without throwing when a user
abandoned the interactive wizard, so the command telemetry recorded
outcome=error with no errorClass/errorDetail — an unactionable blank in
the errors dashboard, where most ktx setup "errors" were really people
backing out of the wizard.

Add annotateCommandOutcome() to the command span so the setup flow (the
decision-maker) records the true outcome: genuine step failures and
--no-input missing input become outcome=error with a self-diagnosing
reason, while interactive abandonment and project cancellation become
outcome=aborted and drop out of the error view.

Unify the exit code and telemetry through setupTerminalOutcome() so they
can never diverge: aborts now exit 0 (matching the entry-menu Exit,
project cancel, and a confirmed Ctrl+C), while failures and automation
errors still exit 1.

* fix(cli): treat non-TTY setup missing-input as an error, not an abort

setupTerminalOutcome classified `missing-input` by `args.inputMode`, but
`auto` only means "interactive if a TTY is attached". A piped/CI `ktx
setup` without `--no-input` and without `--yes` is still `auto`, yet the
project and agents steps return `missing-input` there without ever
prompting (e.g. "pass --yes to create a project outside an interactive
terminal"). Classifying that as `aborted` made a broken automation run
exit 0 — a silent failure.

Key the classification off actual interactivity instead: input enabled
AND `io.stdout.isTTY === true`. Non-interactive missing-input now exits
1 with a `KtxSetupMissingInput` reason; only a genuine interactive abort
exits 0. Adds a non-TTY regression test and fixes the abandonment test
to use a real TTY.
2026-06-09 12:53:15 +02:00
Andrey Avtomonov
66517fc320
feat(cli): add Slack community CTA on errors, crashes, setup, and help (#277)
* feat(cli): show Slack CTA on help and unexpected errors

* feat(cli): show Slack CTA after crashes

* feat(setup): show Slack community note after setup

* chore: refresh Python lockfile versions
2026-06-09 12:22:56 +02:00
Andrey Avtomonov
6b2f7c3365
fix(cli): ensure git committer identity during ktx setup (#276)
* fix(cli): ensure git committer identity during ktx setup

ktx setup threw "Failed to initialize git repository" when the project
directory was already a git repo with no commits and the machine had no
configured git identity (e.g. a fresh Mac with no ~/.gitconfig).
GitService only set the identity on the path where it created the repo
itself, so the bootstrap commit had no resolvable committer.

Carry ktx's identity via GIT_AUTHOR/GIT_COMMITTER env on the shared
git client so every commit succeeds regardless of whether ktx created
the repo, without mutating the user's repo config. Also preserve the
underlying git error when rethrowing so the failure is diagnosable in
telemetry and actionable for the user.

* chore: sync uv.lock ktx-daemon and ktx-sl versions to 0.10.0
2026-06-09 12:10:02 +02:00
github-actions[bot]
bd3a375081 chore: refresh star history chart [skip ci] 2026-06-09 07:21:47 +00:00
Luca Martial
e5425b51a3
docs: align introduction subtitle width with page content (#275)
The introduction page is special-cased as a hero in the docs route, so it
hand-rolls its own title and subtitle instead of using Fumadocs'
DocsTitle/DocsDescription. The subtitle was capped at max-w-2xl (672px),
wrapping ~230px narrower than the heading and body, which read as
misaligned compared to every other docs page. Match the heading's
max-w-full so the subtitle fills the same content column.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 00:49:38 -04:00
Luca Martial
8050b59f6e
docs: consolidate AI Resources into a single page (#274)
* docs: consolidate AI Resources into a single page

The AI Resources section was four pages (agent-quickstart, markdown-access,
agent-instructions, prompt-recipes) that repeated the same docs-consumption
guidance. Collapse them into one page at /docs/ai-resources covering markdown
endpoints, retrieval order, the task router, agent instructions, prompts, and
guardrails.

Also fix a stale claim: the page actions are a single "Copy as Markdown"
button, not the documented "Copy MD / View MD / Copy MDX" trio.

Update the cross-references in README, the introduction cards, the quickstart,
and the llms.txt entry points to the consolidated page.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(docs-site): redirect retired AI Resources slugs, preserving .md route

Redirect the retired per-page slugs (/docs/ai-resources/*) to the consolidated
page. Because Next evaluates redirects before the .md rewrite, a single
catch-all would 308 a cached per-page Markdown URL to the HTML page and break
the agent Markdown contract. Match the .md variant first and keep its suffix so
it lands on /docs/ai-resources.md.

Extend the routing test to assert both the HTML and .md redirects, and that
following the .md URL end to end serves text/markdown.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: move AI Resources under the Community & Resources section

As a single page, AI Resources rendered as an orphaned, unbolded link wedged
between the top-level multi-page sections instead of as a section of its own.
Move it under Community (renamed "Community & Resources") so it renders as a
normal child link, consistent with how the single-page Configuration section
already works.

Redirect the former top-level URL and the retired per-page slugs (HTML and .md,
the .md variants first so cached Markdown URLs keep their suffix) to the new
home, relabel the llms.txt group to match, and repoint the README, introduction,
quickstart, and llms.txt cross-links.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 00:28:56 -04:00
Luca Martial
7ece0b63d3
docs: document upgrading to the latest ktx version (#273)
* docs: document upgrading to the latest ktx version

Install instructions existed but nothing told users how to upgrade an
existing install. Add a minimal upgrade note to the README and to the
quickstart install section showing `npm install -g @kaelio/ktx@latest`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* nitpick

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 20:10:36 -04:00
Luca Martial
07bbdefa14
docs: remove product switcher from docs nav (#272)
The docs site nav carried a "Products" dropdown listing both ktx and
the legacy Kaelio agent platform. On the ktx docs, a co-equal product
switcher framed ktx as one of two products and gave the unrelated
legacy product equal billing. Remove it so the ktx docs stay focused;
cross-product discovery belongs at the docs.kaelio.com apex, not in the
ktx nav.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 19:53:29 -04:00
github-actions[bot]
50dec7bf64 chore: refresh star history chart [skip ci] 2026-06-08 18:55:50 +00:00
semantic-release-bot
48676c74fa chore(release): 0.10.0 [skip ci]
## [0.10.0](https://github.com/Kaelio/ktx/compare/v0.9.0...v0.10.0) (2026-06-08)

### Features

* add GitHub star nudges to CLI build view and docs sidebar ([#271](https://github.com/Kaelio/ktx/issues/271)) ([795a974](795a97485a))
* **cli:** add channel-aware update notifier ([#265](https://github.com/Kaelio/ktx/issues/265)) ([698efdc](698efdcef8))
* **cli:** add ingest LLM rate-limit governor with paced retries ([#261](https://github.com/Kaelio/ktx/issues/261)) ([c3d8ced](c3d8cedb0b))
* **mysql:** implement columnStats using INFORMATION_SCHEMA.STATISTICS ([#233](https://github.com/Kaelio/ktx/issues/233)) ([18245c2](18245c2373))
* **setup:** apply per-role LLM model presets, remove --llm-model ([#268](https://github.com/Kaelio/ktx/issues/268)) ([2c18a62](2c18a62de4))
* **setup:** wizard prompt tweaks and quieter query-history filter output ([#259](https://github.com/Kaelio/ktx/issues/259)) ([c2beaf7](c2beaf7d55))
* **telemetry:** collect PostHog $exception error reports in CLI and daemon ([#262](https://github.com/Kaelio/ktx/issues/262)) ([fb7b94b](fb7b94b60e))

### Bug Fixes

* **docs-site:** stop doubling the /ktx basePath on alias-host redirects ([#263](https://github.com/Kaelio/ktx/issues/263)) ([d3e20df](d3e20df1d5))
* **ingest:** drive work-unit progress from tool calls, not turn counts ([#269](https://github.com/Kaelio/ktx/issues/269)) ([2896f9f](2896f9fb91))
* **sl:** stop baking drift-prone counts into overlay summaries ([#270](https://github.com/Kaelio/ktx/issues/270)) ([5232578](5232578d44))
* **telemetry:** preserve driver error class and code in connection_test ([#260](https://github.com/Kaelio/ktx/issues/260)) ([ec7edf8](ec7edf8f50))

### Documentation

* add serving-phase diagram to the introduction page ([#264](https://github.com/Kaelio/ktx/issues/264)) ([377f21a](377f21acd7))
* minor README and docs-site touch-ups ([#266](https://github.com/Kaelio/ktx/issues/266)) ([bf1fe97](bf1fe9748e))
* **site:** add Products dropdown to ktx docs navbar ([#267](https://github.com/Kaelio/ktx/issues/267)) ([dc39eb7](dc39eb7ef9))

### Other Changes

* refresh star history chart [skip ci] ([0d0ea55](0d0ea55184))
* refresh star history chart [skip ci] ([2914407](2914407f09))
* refresh star history chart [skip ci] ([d142274](d14227468b))
* refresh star history chart [skip ci] ([5a88210](5a8821073b))
* refresh star history chart [skip ci] ([8eb1cd3](8eb1cd3e79))
2026-06-08 14:47:15 +00:00
Andrey Avtomonov
795a97485a
feat: add GitHub star nudges to CLI build view and docs sidebar (#271)
* feat: load star count during context builds

* docs: document star prompt opt-out

* fix: initialize demo context star count

* feat(docs-site): add GitHub star count widget to docs sidebar

* test: isolate star-prompt build-view tests from ambient CI env
2026-06-08 16:14:56 +02:00
Andrey Avtomonov
5232578d44
fix(sl): stop baking drift-prone counts into overlay summaries (#270)
The auto-generated semantic-layer overlay description embedded
measure/segment/column counts that were computed once and never
recomputed, so the summary drifted and misreported its source after
measures were later appended. Make the auto fallback count-free, since
those counts are already rendered live from the body at `ktx sl list`/
`read` time; this removes the drift class without ever overwriting
human-authored descriptions (the fill-only-when-empty guard is untouched).

Adds a regression test that fails on main and passes after the fix, plus
guards for description preservation and the no-measures fallback.
2026-06-08 15:58:12 +02:00
Andrey Avtomonov
2c18a62de4
feat(setup): apply per-role LLM model presets, remove --llm-model (#268)
* feat(setup): write per-role llm model presets

* feat(setup): remove llm model setup flag

* chore(setup): update llm preset guidance

* docs(setup): document llm model presets

* chore(release): sync uv.lock to 0.9.0

* fix(cli): make sl query --execute work on secret-backed connections

sl query --execute used a parallel SQL executor (createDefaultLocalQueryExecutor)
that passed connection.url verbatim into pg, so file:/env: secret references
failed with "SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a string".

Collapse onto the connector-based executor already used by MCP and ingest
(createKtxCliIngestQueryExecutor), which resolves secret references and supports
every driver. Delete the now-dead local/postgres/sqlite query executors, their
tests, and the orphaned hasLocalQueryExecutor driver flag.

* docs(agents): require one implementation per capability

Add a design-reasoning default and a matching self-check question telling agents
to route callers through a single shared implementation of a capability rather
than forking a parallel one, and to fix the shared layer rather than patch one
branch. Encodes the lesson from a divergent SQL-execution-path bug, stated
generally.

CLAUDE.md is a symlink to AGENTS.md, so both agent-instruction files are covered.
2026-06-08 15:30:48 +02:00
Andrey Avtomonov
2896f9fb91
fix(ingest): drive work-unit progress from tool calls, not turn counts (#269)
The ingest HUD showed "step 70/40" because the Claude subscription runtime
re-derived a per-turn counter that could not match the SDK's num_turns and
overshot the maxTurns budget. Replace the turn-based work_unit_step heartbeat
with a real, observed tool-call count (no denominator), report
metrics.stepCount from the SDK's authoritative num_turns, and delete the
brittle countsAsAssistantTurn denylist plus the now-unused onStepFinish
callback across the runtime port and all three runtimes. Reconcile and curator
progress move to the same tool-call heartbeat.
2026-06-08 15:30:35 +02:00
Mayorkun Ayanshina
18245c2373
feat(mysql): implement columnStats using INFORMATION_SCHEMA.STATISTICS (#233)
* feat(mysql): implement columnStats using INFORMATION_SCHEMA.STATISTICS

Enable column cardinality statistics for the MySQL connector by querying
INFORMATION_SCHEMA.STATISTICS, which provides index-based cardinality
estimates without requiring additional permissions.

- Add generateColumnStatisticsQuery() to KtxMysqlDialect
- Add getColumnStatistics() and columnStats() to KtxMysqlScanConnector
- Flip columnStats capability from false to true
- Add MysqlStatsRow and KtxMysqlColumnStatisticsResult interfaces
- Add tests for dialect query generation and connector stats retrieval
- Update dialect conformance fixture for mysql

* fix(mysql): filter to leading index columns to avoid inflated cardinality

Add AND SEQ_IN_INDEX = 1 to INFORMATION_SCHEMA.STATISTICS query to
ensure only leading index columns are returned. For composite indexes,
non-leading columns report the cardinality of the index prefix rather
than the column's own distinct count, which inflates distinctCount.

Add regression test asserting SEQ_IN_INDEX = 1 is present in the query.

* fix: add trailing newline to dialect.test.ts

---------

Co-authored-by: Andrey Avtomonov <andreybavt@gmail.com>
2026-06-08 12:21:19 +02:00
github-actions[bot]
0d0ea55184 chore: refresh star history chart [skip ci] 2026-06-08 07:52:04 +00:00
Andrey Avtomonov
dc39eb7ef9
docs(site): add Products dropdown to ktx docs navbar (#267)
Surface ktx (primary) and Kaelio Platform docs via a navbar product
menu so users can switch between the two docs sites; ktx stays first.
2026-06-07 23:15:21 +02:00
github-actions[bot]
2914407f09 chore: refresh star history chart [skip ci] 2026-06-07 07:30:35 +00:00
Luca Martial
bf1fe9748e
docs: minor README and docs-site touch-ups (#266)
- Link the Y Combinator badge and the docs "by Kaelio" label
- Add a maintainer line to the README
- Set the npm author field on @kaelio/ktx

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 22:32:08 -04:00
Andrey Avtomonov
698efdcef8
feat(cli): add channel-aware update notifier (#265)
* feat(cli): show cached update notices after commands

* docs(cli): describe update notices

* fix(cli): type update check environment

* fix(cli): decouple update notice display from refresh and harden suppression

Display a cached "update available" notice based solely on the lastNoticeAt
24h throttle, independent of checkedAt refresh freshness, matching the design's
independent display/refresh decisions. Suppress the check unconditionally under
--json, CI, and non-TTY before consulting output-mode preferences, so a
KTX_OUTPUT=pretty override can no longer make CI/non-TTY contexts phone npm.
2026-06-06 10:42:10 +02:00
Luca Martial
377f21acd7
docs: add serving-phase diagram to the introduction page (#264)
* feat(docs): add serving-phase diagram to the introduction page

The introduction's "How ktx works" section described both the ingest and serve sides but only rendered the ingestion diagram. Add a live, theme-aware React Flow diagram for the serving phase (agent <-> ktx via MCP -> context layer + database) so both phases are shown, with a matching content test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(diagram-studio): relabel context edge and use right-angle routing

The hub->context edge searches and reads definitions, not just searches; relabel it "search + read". Route the serving search/read-only edges with smoothstep (right angles) to match the docs diagram. (The README PNG is a baked export and is unchanged until re-exported from the studio.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(docs): point product-mechanics assertions at the FlowCanvas wrapper

product-mechanics renders via the shared FlowCanvas wrapper, so the ReactFlow config (nodesDraggable, zoomOnScroll, etc.) lives there now. Update the stale assertions that still expected those literals inline, fixing a pre-existing test failure.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(serving-diagram): shrink the boxes and drop OpenCode from the agent list

Reduce node dimensions, font sizes, padding, and the canvas height so the serving diagram renders ~25% smaller and more compact. Remove OpenCode from the agent's listed clients.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 19:22:45 -04:00
Luca Martial
d3e20df1d5
fix(docs-site): stop doubling the /ktx basePath on alias-host redirects (#263)
ktx.sh/ and docs.ktx.sh/ redirected to
https://docs.kaelio.com/ktx/ktx/docs/... (note the doubled /ktx) and 404'd.

The host-agnostic `source: "/"` redirect ran before the alias-host
canonicalizers, so it injected the /ktx basePath into the path on the alias
domains, which the alias catch-all then prepended a second time.

Reorder redirects() so alias-host canonicalization runs first, leaving the
generic root/docs rules for the local/canonical host only. The /stars
exclusion stays because redirects run before beforeFiles rewrites.

Add Host-spoofing regression tests (the prior tests only used localhost,
which never exercised the alias-host rules) and remove the vestigial
website/vercel.json, which the live ktx.sh routing already bypasses.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 15:05:22 -04:00
github-actions[bot]
d14227468b chore: refresh star history chart [skip ci] 2026-06-05 18:44:32 +00:00
Andrey Avtomonov
fb7b94b60e
feat(telemetry): collect PostHog $exception error reports in CLI and daemon (#262)
* feat(telemetry): add node exception reporter

* feat(telemetry): report node cli exceptions

* feat(telemetry): add daemon exception reporter

* feat(telemetry): report daemon exceptions

* docs(telemetry): document error reports

* fix(telemetry): pass redaction snapshots from node call sites

* test(telemetry): verify prepared node exception payload

* fix(telemetry): close daemon exception lifecycle gaps

* test(telemetry): verify prepared daemon exception payload

* test(telemetry): close error collection acceptance gaps

* test(telemetry): close posthog exception acceptance gaps
2026-06-05 19:36:21 +02:00
Andrey Avtomonov
c3d8cedb0b
feat(cli): add ingest LLM rate-limit governor with paced retries (#261)
* feat(cli): add ingest rate limit governor

* feat(cli): wire ingest rate-limit config

* feat(cli): report provider rate-limit signals

* feat(cli): show ingest rate-limit waits

* fix(cli): complete rate-limit event coverage

* fix(cli): abort ingest provider calls cleanly

* fix(cli): propagate ingest cancellation

* fix(cli): reject pre-aborted ingest rate-limit waits

* fix(cli): honor Claude rate-limit reset waits

* fix(cli): retry thrown Codex rate-limit failures

* fix(cli): type Claude rate-limit result details

* fix(cli): emit ingest rate-limit countdowns from rejected signals

* fix(cli): report ai sdk rate-limit header utilization

* fix(cli): gate LLM rate-limit retries on the governor budget

The AI SDK and Codex runtimes retried 429 / opaque rate-limit failures up
to 6-7 times with no backoff when constructed without a RateLimitGovernor
(scan, memory, setup) or with pacing disabled, ignoring Retry-After and
worsening the limit. The outer retry loop only cooperates with the
governor's pause, so without active pacing there is no backoff to apply.

Route the retry bound through a single source: RateLimitGovernor
.maxRetryAttempts(), which returns retry.maxAttempts when enabled and 1
(no outer retry) when absent or disabled. All three runtimes (ai-sdk,
codex, claude-code) now use it, so ingest.rateLimit.retry.maxAttempts
genuinely controls attempts and the hard-coded 6 (plus Codex's off-by-one
extra attempt) is gone. Backend-native retry (e.g. the AI SDK's maxRetries)
still handles transient 429s.

Also correct the ktx.yaml docs for maxWaitMs (caps each wait, not the whole
run) and maxAttempts, and sync uv.lock ktx-sl/ktx-daemon to 0.9.0.
2026-06-05 12:10:27 +02:00
github-actions[bot]
5a8821073b chore: refresh star history chart [skip ci] 2026-06-04 18:53:21 +00:00
Andrey Avtomonov
ec7edf8f50
fix(telemetry): preserve driver error class and code in connection_test (#260)
Native connector test failures were flattened to `new Error(message)`,
collapsing every driver's error class to `Error` and dropping `.code` /
`.number`. connection_test telemetry could therefore not tell a SQL Server
login rejection (ELOGIN / 18456) apart from a network or TLS error, and the
only field that varied was a raw message.

Connectors now return `connectorTestFailure(error)`, which preserves the
original driver error as `cause`, and `testNativeConnection` re-throws that
cause. `scrubErrorClass` then records the real class (e.g. ConnectionError)
and `formatErrorDetail` keeps the code prefix (e.g. "ELOGIN: ..."). The
helper is the single source of truth for the failure shape across all seven
native connectors. User-facing terminal output is unchanged.
2026-06-04 14:51:14 +02:00
Andrey Avtomonov
c2beaf7d55
feat(setup): wizard prompt tweaks and quieter query-history filter output (#259)
Setup wizard flow tweaks:
- Add a reveal-tail password prompt (reveal-password-prompt.ts) that unmasks
  the last few characters of a typed/pasted secret, and wire it into the setup
  prompt adapter in place of clack's password(); adds the @clack/core dep.
- Reorder wizard select options: surface "Paste a key" before the
  environment-variable option across embeddings/models/sources, promote
  Metabase/Notion in the source list, put Git URL before Local path, reorder
  the Notion crawl-mode choices, and relabel the sources "Done" action.

Query-history filter picker output:
- Collapse the per-template parse-failure lines into a single count in the
  setup output and route the full template-id list to --debug stderr.
- Model parse failures as a structured parseFailedTemplateIds field instead of
  warning strings.
- Add a privacy-safe query_history_filter_completed telemetry event
  (counts/enums only), mirrored into the Python daemon schema.
2026-06-04 14:11:08 +02:00
github-actions[bot]
8eb1cd3e79 chore: refresh star history chart [skip ci] 2026-06-04 07:45:37 +00:00
semantic-release-bot
7ba948a135 chore(release): 0.9.0 [skip ci]
## [0.9.0](https://github.com/Kaelio/ktx/compare/v0.8.0...v0.9.0) (2026-06-03)

### Features

* add codex llm backend for ktx runtime work ([#253](https://github.com/Kaelio/ktx/issues/253)) ([494618a](494618ab14))
* **cli:** consistent connection setup recovery and build-time gate ([#257](https://github.com/Kaelio/ktx/issues/257)) ([ce1516b](ce1516b357))
* **cli:** guide next action at end of ktx setup, not reruns ([#256](https://github.com/Kaelio/ktx/issues/256)) ([45aa95d](45aa95d2cc))
* **cli:** stream plain ktx ingest progress to stderr (KLO-726) ([#251](https://github.com/Kaelio/ktx/issues/251)) ([13774bf](13774bfcef))
* **query-history:** scope mining to modeled schemas by default ([#258](https://github.com/Kaelio/ktx/issues/258)) ([e70ae1e](e70ae1e63b))
* **telemetry:** include error details for failures ([#254](https://github.com/Kaelio/ktx/issues/254)) ([6da8c34](6da8c3452a))

### Bug Fixes

* **ingest:** recover textual-conflict gate failures; fix query-history adapter ([#255](https://github.com/Kaelio/ktx/issues/255)) ([f5dea9a](f5dea9a089))

### Other Changes

* refresh star history chart [skip ci] ([9d3a0b7](9d3a0b751d))
* refresh star history chart [skip ci] ([74c6076](74c6076b72))
* refresh star history chart [skip ci] ([d01abe6](d01abe6f3c))
* revert repo references to Kaelio/ktx and remove rename-resilience ([#252](https://github.com/Kaelio/ktx/issues/252)) ([41e20c9](41e20c9ce7)), closes [#250](https://github.com/Kaelio/ktx/issues/250) [#250](https://github.com/Kaelio/ktx/issues/250)
2026-06-03 21:50:59 +00:00
Andrey Avtomonov
e70ae1e63b
feat(query-history): scope mining to modeled schemas by default (#258)
* feat(query-history): structure SQL analysis table refs

* feat(query-history): qualify SQL analysis table refs

* feat(query-history): wire modeled scope floor through ingest

* chore(query-history): verify scope floor

* test(query-history): align daemon SQL batch endpoint contract

* feat(query-history): build scope from same-run scan catalog

* feat(query-history): fail open on scope-floor catalog failures

* chore(query-history): verify scope-floor v1 closure

* refactor(query-history): share scope membership

* feat(setup): apply derived query history filters

* docs: document derived query history filters

* fix(query-history): redact filter picker LLM prompt SQL

* fix(setup): run filter picker SQL analysis through managed daemon

* chore(query-history): verify filter picker v1 closure

* fix(query-history): fail open on partial service-account attribution

* fix(query-history): aggregate BigQuery users by execution count

* fix(query-history): aggregate Snowflake users by execution count

* fix(query-history): use BigQuery query info hash
2026-06-03 17:19:42 +02:00
Andrey Avtomonov
ce1516b357
feat(cli): consistent connection setup recovery and build-time gate (#257)
* feat(cli): block context build when a required connection fails its live test

A context build can take several minutes, so a connection that is
unreachable or misconfigured should stop the build up front instead of
failing partway through. Before the build starts, run a live connection
test for every primary- and context-source connection the build depends
on.

Each test's output is captured in a discarded buffer so raw error text
(and database paths) never reach the user; failures are surfaced only by
connection id and connector type, with a pointer to `ktx connection test
<id>` for the underlying error.

- Interactive setup lets the user fix the connection and retry without
  restarting, re-resolving targets so an added/removed/reconfigured
  connection is honored.
- `--no-input` exits non-zero and writes a failed context state with a
  failureReason, so scripts stop early and setup never reads as ready.

Extract the buffered command IO helper out of setup-databases into
src/io/buffered-command-io.ts so both call sites share one implementation.

* feat(cli): use recovery primitive for database setup

* feat(cli): use recovery primitive for source setup

* docs: document setup connection recovery

* fix(cli): close database recovery gaps

* fix(cli): target failing project in gate hint and preserve missing-input

Address two review findings on the connection-recovery work:

- The connection-gate failure hint emitted `ktx connection test <id>` with no
  --project-dir, so a setup run started with `--project-dir ./analytics` pointed
  users at cwd/KTX_PROJECT_DIR instead of the project that just failed. Emit the
  resolved project dir, matching the contextBuildCommands convention.

- The non-interactive database configure path returned `cancelled`, which the
  recovery primitive collapses to `failed`. Sibling paths still report
  `missing-input` for absent flags, so incomplete-flag runs were
  indistinguishable from real connection failures. The database wrapper now
  tracks the configure missing-input signal and restores the `missing-input`
  step status; the shared primitive keeps its four outcomes.
2026-06-03 11:08:46 +00:00
Andrey Avtomonov
f5dea9a089
fix(ingest): recover textual-conflict gate failures; fix query-history adapter (#255)
* fix(ingest): recover textual-conflict gate failures; fix query-history adapter

Two latent gaps in the isolated-diff local-ingest pipeline that can abort an
otherwise-successful ingest:

- Metabase: when a work-unit patch hit both a textual conflict and a post-merge
  dangling sl_ref, the after-textual-resolution branch returned a hard
  semantic_conflict and rolled back the whole job. It now runs the same
  repairGateFailure recovery the clean-apply branch already uses (re-validate,
  then commit the union of resolved + repaired paths), reaching parity.

- Query history: the historic-sql adapter was registered only when ktx.yaml had
  context.queryHistory.enabled=true, so `--query-history` threw "Adapter not
  available for local ingest". Registration now resolves the dialect from driver
  capability, since the explicit --query-history request is itself the opt-in;
  the config-gated helper is unchanged for status/setup/probes.

Adds the previously-missing tests for both paths.

* chore: sync uv.lock to 0.8.0 (regenerated with pinned uv 0.11.11)

* fix(ingest): drop ktx's own scan probes and dedup tables in query history

Query history (historic-sql) mined two kinds of noise back into context:

- ktx's own warehouse scan emits relationship- and column-profiling probes
  (the relationship_profile_values aggregation and the child_values/parent_values
  FK-overlap CTEs) into pg_stat_statements. shouldDropBySql now filters these
  ktx-owned, dialect-stable signatures so ktx introspection is not ingested as
  usage history.

- The same physical table appears both bare (accounts, via search_path) and
  schema-qualified (orbit_raw.accounts), producing duplicate per-table work
  units. canonicalizeTableIdentifiers collapses a bare name into its unique
  qualified form before work-unit keying; ambiguous names are left untouched.

On the orbit demo this removes ~35% of sampled query templates (ktx self-probes)
and ~45 duplicate per-table work units.

* docs(agents): add Design Reasoning Defaults section
2026-06-03 13:05:59 +02:00
github-actions[bot]
9d3a0b751d chore: refresh star history chart [skip ci] 2026-06-03 07:50:39 +00:00
Andrey Avtomonov
45aa95d2cc
feat(cli): guide next action at end of ktx setup, not reruns (#256)
Re-running setup was the dominant action for installs that completed setup but never ingested. Classify completion (incomplete | needs-context | needs-agents | ready) and drive one obvious next action per state: route a config-complete project straight to the build, point unbuilt-context users at `ktx ingest` instead of re-running setup or dropping to a bare shell, and confirm readiness for fully-set-up projects rather than reopening the edit menu.
2026-06-03 01:00:21 +02:00
Andrey Avtomonov
cb6a67c2d7 Make telemetry reliable across interrupts and headless installs
Three reliability gaps surfaced while auditing why PostHog numbers were
untrustworthy:

1. Interrupted commands lost their events. capture() is fire-and-forget and the
   only flush guarantee lived in a finally block, which SIGINT/SIGTERM skip — so
   Ctrl-C'ing a long ingest or an MCP client killing 'ktx mcp stdio' dropped the
   command event and any queued events. Add SIGINT/SIGTERM handlers (real-process
   entry only; never under test/programmatic io) that mark the active command
   span aborted, emit it, drain the emitter, then exit. Idempotent with the
   normal finally path via the single-consume command span.

2. Headless-first installs were invisible. loadTelemetryIdentity refused to mint
   an installId unless stdout was a TTY, so a machine whose first run was an
   IDE-launched MCP server or a script emitted nothing, ever. Mint on first run
   regardless of surface (still honoring CI/DO_NOT_TRACK/KTX_TELEMETRY_DISABLED),
   writing the one-time notice to stderr — safe under the MCP stdio protocol,
   which reserves stdout. Drop the now-unused stdoutIsTTY option.

3. No guard against silent emit regressions (the 0.7.0 scan_completed blackout).
   Add tests: the shared executePublicIngestTarget chokepoint emits exactly one
   ingest_completed on success and on the preflight-failure branch, and a
   database target invokes the scan that emits scan_completed; plus coverage for
   the aborted-flush helper.

Identity is unchanged otherwise: every event still attributes to the installId
in ~/.ktx/telemetry.json. No event/field changes, so Node<->Python schema parity
is untouched. Docs updated to reflect first-run-on-any-surface activation.
2026-06-02 23:19:37 +02:00
Andrey Avtomonov
2334a4b6e3 Emit ingest_completed once per target on every ingest path
emitIngestCompleted was called only in runKtxPublicIngest's plain/json loop,
so the foreground 'ktx ingest' view and all of 'ktx setup' — which delegate to
runContextBuild -> executePublicIngestTarget — never emitted the event. That
left ingest_completed near-useless for measuring ingestion.

Move the emit into executePublicIngestTarget, the single per-target chokepoint
every entrypoint funnels through: a thin wrapper now captures timing, runs the
existing steps (extracted to runIngestTargetSteps), and emits exactly once. The
telemetry echo targets deps.runtimeIo (the real user stream) so a capture
buffer used for step output doesn't swallow it. Thread project through the
context-build call site. No schema/field changes, so Node<->Python telemetry
parity is unaffected.

Add tests: the shared chokepoint emits exactly one ingest_completed for any
caller, and a multi-target run emits one per target with no double-emit.
2026-06-02 20:03:27 +02:00
Andrey Avtomonov
6da8c3452a
feat(telemetry): include error details for failures (#254) 2026-06-02 17:23:51 +02:00
Andrey Avtomonov
494618ab14
feat: add codex llm backend for ktx runtime work (#253)
* feat: add codex sdk runner foundation

* feat: parse codex runtime events

* feat: expose codex runtime mcp tools

* feat: add codex llm runtime

* feat: wire codex llm backend

* test: avoid Array.fromAsync in codex runner test

* docs: document codex llm backend

* fix: tighten codex runtime config ownership

* fix: use codex sdk env and thread options

* fix: parse codex sdk event shapes

* test: add codex backend live smoke

* docs: clarify codex backend isolation

* fix: drive codex loop metrics from mcp events

* fix: enforce codex local step budget

* docs: disclose codex isolation limits

* fix: count all codex agent steps and stream step callbacks live

The agent-loop step budget only counted completed mcp_tool_call items, so
built-in command_execution steps (which the public Codex SDK/CLI surface can
still expose) never decremented the budget, letting ingest/reconciliation run
past stepBudget until Codex stopped on its own. onStepFinish was also replayed
only after the whole stream drained, so live work_unit_step / reconciliation
progress appeared stuck until the Codex process exited.

collectEvents is now the single live step accumulator: it counts every
completed agent-action item via a shared isCompletedAgentStep predicate
(command_execution, mcp_tool_call, file_change, web_search), fires onStepFinish
as each step completes, and enforces the budget on that broader count. A
no-tool turn still counts as one step. toolFailures stays MCP-specific, since a
non-zero command exit is normal agent exploration, not a loop failure.

* test: align ingest llm-guard assertions with codex backend

The skip-llm ingest guard message now lists codex as a valid backend and
mentions a Claude Code/Codex session plus a codex setup hint, but this slow
suite test still asserted the pre-codex wording. Update it to match the
production message (already covered by the local-bundle-runtime unit test) and
add the codex setup-line assertion.

* fix: treat codex error:null tool calls as success

The Codex SDK serializes error: null on successful mcp_tool_call items, so
the failure check (item.error !== undefined) flagged every successful tool
call as failed with the empty-payload default "Codex turn failed". This
killed every ingest work unit under the codex backend before it could
produce a patch.

Key on status === 'failed' (authoritative, always set) and only treat a
populated error object as a failure. Add a regression test built from a
verbatim real-SDK event capture.

* fix: default codex backend to gpt-5.5 and report real probe errors

The previous default gpt-5.3-codex is an API-key-only model that the OpenAI
API rejects under ChatGPT-account (subscription) auth, so codex status/setup
failed with a misleading "authentication is not usable" message even though
auth was fine.

- Default codex model is now gpt-5.5 (works on both subscription and API-key
  auth); the curated setup picker offers gpt-5.5 / gpt-5.4 / gpt-5.4-mini and
  keeps free-form entry for account-specific ids (e.g. gpt-5.3-codex-spark).
- runCodexAuthProbe now distinguishes "model not available" from an auth
  failure and surfaces the real API error: collectEvents retains stream
  events when the SDK throws on a non-zero exit, and the API error JSON
  envelope is unwrapped to its human-readable message.
- The Codex isolation warning now renders inside the clack setup frame.
- Docs updated to gpt-5.5 with a note that *-codex ids require API-key auth.

* fix: require llm.models.default in status and match codex probe remediation

Status reported a project ready when a non-none LLM backend was configured
without llm.models.default, but the runtime (resolveModelSlots) hard-requires
it, so ingest/scan/memory threw after `ktx status` said the project was usable.
buildLlmStatus now fails for any non-none backend missing models.default and no
longer invents a fallback model for claude-code/codex.

Codex probe failures now carry a category-matched fix: a model-access failure
steers the user at llm.models.default instead of the auth/install remediation.
runCodexAuthProbe returns the fix and status consumes it; the message stays
self-sufficient so setup output is unchanged.

Docs: README now lists the codex backend and local Codex auth; ktx-setup.mdx
states --llm-model only accepts codex/default or gpt-*/codex-* ids.

Repaired four doctor fixtures that configured a backend without models.default
(the now-correctly-blocked config) and added coverage for the new behavior.
2026-06-02 13:57:11 +02:00
github-actions[bot]
74c6076b72 chore: refresh star history chart [skip ci] 2026-06-02 07:46:46 +00:00
Andrey Avtomonov
41e20c9ce7
chore: revert repo references to Kaelio/ktx and remove rename-resilience (#252)
The GitHub repo was renamed back from Kaelio/ktx-ai-data-agents-context to Kaelio/ktx, reverting the URL changes from #250 across package metadata, CI (codecov + star-history slugs), issue/security templates, the release runbook, and docs/install commands.

Also removes the rename-resilience machinery #250 added: semantic-release now reads the repository URL straight from package.json (Kaelio/ktx) again, so the repositoryUrl() derivation in scripts/semantic-release-config.cjs, its tests, and the rename note in docs/release.md are no longer needed.
2026-06-02 00:14:43 +02:00
Andrey Avtomonov
13774bfcef
feat(cli): stream plain ktx ingest progress to stderr (KLO-726) (#251)
* feat(cli): share public ingest progress adapter

* feat(cli): stream plain public ingest progress

* test(cli): update plain ingest progress assertions

* chore(cli): satisfy plain ingest progress checks

* fix(artifacts): expect plain ingest stderr progress in installed-CLI smoke

* ci(coverage): make Codecov upload non-fatal and fix repo slug

The Coverage job failed because the Codecov upload returned
'Repository not found' while fail_ci_if_error was true, turning a
Codecov-side issue into a hard CI failure even though all tests pass.

- Set fail_ci_if_error: false on both uploads so Codecov outages or an
  unlinked repo no longer break CI (upload stays best-effort).
- Correct the stale slug Kaelio/ktx -> Kaelio/ktx-ai-data-agents-context
  to match the actual GitHub repo (aligns with main).

* fix(cli): isolate query-history failure capture from scan output

The plain public-ingest progress path passes one captured IO as the
target-level `io`. With progress deps set, both the schema scan and the
query-history ingest resolved their capture to that same shared buffer,
so a non-actionable query-history failure surfaced leftover scan report
text (e.g. "Mode: enriched") as the skipped-facet detail instead of the
real query-history message.

Give the query-history ingest a phase-local capture while preserving the
flow-to-io branch the foreground context-build view relies on.

---------

Co-authored-by: Andrey Avtomonov <7889985+andreybavt@users.noreply.github.com>
2026-06-01 23:31:31 +02:00
github-actions[bot]
d01abe6f3c chore: refresh star history chart [skip ci] 2026-06-01 19:42:24 +00:00
semantic-release-bot
41cccc3448 chore(release): 0.8.0 [skip ci]
## [0.8.0](https://github.com/Kaelio/ktx-ai-data-agents-context/compare/v0.7.0...v0.8.0) (2026-06-01)

### ⚠ BREAKING CHANGES

* **cli:** remove fast mode; ktx ingest always builds enriched context (KLO-721) (#237)

### Features

* **cli:** profile ingest runs and split model vs tool time ([#249](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/249)) ([21744fc](21744fc520))
* **cli:** remove fast mode; ktx ingest always builds enriched context (KLO-721) ([#237](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/237)) ([3f0d11e](3f0d11e07d))
* **cli:** shell completion for commands, flags, and entity names ([#244](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/244)) ([d320d54](d320d54ab2)), closes [#243](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/243)
* README architecture diagrams + React Flow diagram studio ([#245](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/245)) ([ba5bb92](ba5bb92ab7))
* report MCP client telemetry ([#242](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/242)) ([2e5f7f2](2e5f7f25aa))
* **telemetry:** enable PostHog GeoIP enrichment ([#243](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/243)) ([95a2653](95a265323a))
* trim MCP query response payloads ([#240](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/240)) ([25f639f](25f639fba2))

### Bug Fixes

* **brand:** README lockup wordmark in Outfit to match docs-site ([#246](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/246)) ([1959f49](1959f493d6))
* **cli:** align Notion setup credential to --source-auth-token-ref ([#236](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/236)) ([637891f](637891f030))
* **cli:** treat artifact-producing ingests with failures as partial ([#238](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/238)) ([53a6f8d](53a6f8d111))
* **release:** point repository URLs at renamed GitHub repo ([#250](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/250)) ([41f5279](41f52797de))

### Documentation

* **ktx skill:** harden setup guidance from agent-driven demo run ([#247](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/247)) ([5faa16b](5faa16b32c))
* **readme:** add launch video to README hero ([#248](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/248)) ([22ddf55](22ddf5524c))

### Continuous Integration

* normalize star-history.svg trailing newline ([#241](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/241)) ([cbbcf8e](cbbcf8e8bd)), closes [#240](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/240)
* push star-history refresh to protected main with RELEASE_PAT ([#239](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/239)) ([ba06f70](ba06f7078a))
* refresh README star history chart twice daily ([08d08d8](08d08d8ea0))
* stop tombi reformatting uv.lock and sync lock to 0.7.0 ([#235](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/235)) ([8ebc4ce](8ebc4ce107))

### Other Changes

* refresh star history chart [skip ci] ([c196d1f](c196d1f192))
* refresh star history chart [skip ci] ([2058c26](2058c26e84))
* refresh star history chart [skip ci] ([54d6e87](54d6e87733))
* upgrade dependencies and tooling ([#232](https://github.com/Kaelio/ktx-ai-data-agents-context/issues/232)) ([d53cdac](d53cdac366))
2026-06-01 18:09:14 +00:00
Andrey Avtomonov
41f52797de
fix(release): point repository URLs at renamed GitHub repo (#250)
* fix(release): point repository URLs at renamed GitHub repo

The GitHub repo was renamed from Kaelio/ktx to
Kaelio/ktx-ai-data-agents-context. semantic-release reads repositoryUrl
from package.json's repository field and the @semantic-release/github
plugin failed verifyConditions with EMISMATCHGITHUBURL because it no
longer matched the live clone URL.

Update every Kaelio/ktx reference to the renamed repo: package metadata
(root + CLI repository/bugs/homepage), the codecov upload slugs and
star-history slug in CI, the issue-template and security-advisory links,
the release runbook, and all docs/install commands.

* fix(release): derive semantic-release repositoryUrl from the CI repo

@semantic-release/github exact-matches repositoryUrl against the live
GitHub clone_url (no redirect following), so any repo rename re-breaks the
release when repositoryUrl is the static package.json value.

Derive repositoryUrl from the runner's GITHUB_REPOSITORY/GITHUB_SERVER_URL
so it always tracks the current repo name. A future rename (including back
to Kaelio/ktx) now resolves with no code change. Outside CI the option is
omitted, so semantic-release falls back to package.json as documented.

The package.json repository field stays ktx-ai-data-agents-context as
npm-display metadata, decoupled from the release-time match.
2026-06-01 20:07:24 +02:00
Andrey Avtomonov
9133d243e8 Update demo warehouse URL 2026-06-01 16:44:41 +02:00
Andrey Avtomonov
21744fc520
feat(cli): profile ingest runs and split model vs tool time (#249)
* feat(cli): profile ingest runs to find where wall-clock time goes

Add opt-in profiling for `ktx ingest`. Each timed phase, work unit, and
agent loop now records durationMs / step count / token usage in the
trace, and a post-run aggregator rolls them up into a "where did the
time go" report printed to stderr.

Enable per run with KTX_PROFILE_INGEST (1/true -> human table, json ->
raw structured profile) or persistently via `ingest.profile` in
ktx.yaml. The json form emits raw milliseconds, token counts, and a
summary.headline one-line diagnosis so coding agents can parse it
directly; json wins when both env and config request profiling.

- runtime-port: RunLoopMetrics (totalMs, usage, stepCount,
  stepBoundariesMs) plus onMetrics callbacks on text/object generation
- ai-sdk + claude-code runtimes: capture per-loop timing and token usage
- work-unit-executor and stages 3/4: thread metrics into trace events
- ingest-bundle.runner: time worktree / triage / clustering / index /
  reconcile / squash phases and emit the profile in a finally block
  (best-effort; never affects the run outcome)
- ingest-profile: new trace+transcript aggregator with table/json formatters
- config: ingest.profile flag; docs: profiling section in ktx-ingest.mdx

* fix(cli): flush tool-call logs before reading ingest profile

Tool transcripts are appended fire-and-forget so the agent hot path never
blocks on logging. The ingest profiler read them before the writes settled,
so per-work-unit toolMs (and the model-vs-tool split derived from it) could
be incomplete. Track in-flight appends and expose flushToolCallLogs() —
bounded by a timeout so it can never hang — and flush before the profiler
reads the transcript.
2026-06-01 15:49:17 +02:00
Andrey Avtomonov
22ddf5524c
docs(readme): add launch video to README hero (#248)
Add a clickable launch-video poster (linking to YouTube) directly after
the intro note and before the architecture diagrams. GitHub Markdown can
not embed a YouTube player, so the poster image links out instead.
2026-06-01 13:42:42 +00:00
Andrey Avtomonov
5faa16b32c
docs(ktx skill): harden setup guidance from agent-driven demo run (#247)
Fold field-tested fixes into the ktx skill, verified against current CLI source:

- prefer file: secret refs over env: (env: re-resolves per-process and resolves
  empty in later ingest/mcp shells)
- pass --skip-agents on data-only setup runs; explain the trailing agent step's
  misleading exit 1 on otherwise-successful runs
- dbt ignores --source-warehouse-connection-id (maps by table name); required
  only for Metabase/Looker/LookML
- never go silent during slow setup/ingest: poll .ktx mtimes and post progress
  so a long run does not look stuck
- judge readiness from verdict, connections[].status, localStats.semanticLayer
  and wikiPages; perConnection under-reports
- add troubleshooting entries for the 'Run in a TTY' exit 1 and secrets that
  resolve empty only during ingest/mcp
2026-06-01 12:08:58 +00:00
Andrey Avtomonov
1959f493d6
fix(brand): README lockup wordmark in Outfit to match docs-site (#246) 2026-06-01 11:18:37 +00:00