Skip to content

v0.1.5

Choose a tag to compare

@db-tycoon-stephen db-tycoon-stephen released this 07 May 17:48
· 53 commits to main since this release
30f3882

Tycoon v0.1.5

Released: 2026-05-03

Headline

v0.1.5 is a polish + correctness release. The big-ticket features
landed in v0.1.4 (data sync, observability-as-data, MkDocs site,
CI/CD automation); v0.1.5 hardens the path users actually walk.

The four themes worth opening with:

  • AI agent setup is now one command. tycoon init chains the AI
    agent setup automatically when the user picks a provider in the
    wizard. The wizard auto-detects running LM Studio / Ollama on
    their default ports (:1234 / :11434) and short-circuits the
    7-option menu to a 1-keystroke Detected Ollama — use it? [Y/n]:
    confirm. Local providers get a model-install offer for the
    recommended Qwen 2.5 Coder 7B Instruct (Q4_K_M, ~4.7 GB) —
    Ollama auto-pulls, LM Studio gets GUI steps. Ends issue #7
    (4/6 → 6/6 sub-asks complete).

  • LLM config moved to tycoon register llm. Symmetric with
    tycoon register dbt and tycoon register warehouse — point
    tycoon at an external resource, record the linkage in
    tycoon.yml. Removed tycoon ask init and
    tycoon ask install-model; the ask namespace is now reserved
    for analytics endpoints (chat, sync, context, doctor, skills,
    mcp). Read-only LLM probing stays in ask doctor.

  • Auto-scaffold dbt staging from dlt schema. The
    tycoon data analyze command (which has existed since v0.1.1)
    is now sentinel-protected, auto-triggered after
    tycoon data sources run, and supports --all for multi-source
    scaffolding. The user-visible flow collapses from
    init → ingest → analyze → transform to just
    init → ingest → transform for the happy path. Re-runs preserve
    hand-edits via the @generated by tycoon analyze sentinel; pass
    --force to override.

  • Three real bugs caught and fixed. The new e2e coverage
    surfaced #22 (filesystem CSV ingest defaulted to append, not
    replace), #23 (data sync failed entire run on any view
    referencing an unattached catalog), and #24 (capture_dlt
    silently failed for filesystem source due to a DuckDB
    intra-process connection conflict). All three fixed in this
    release.

What landed

Issue close-out

  • #7 — UX: one-command setup for MotherDuck + Nao + LM Studio.
    Closed completely. The two deferred sub-asks from v0.1.4:
    • §3 smart include_schemas defaults. tycoon register llm
      seeds ask.exclude_schemas with conservative noise patterns
      (information_schema, pg_catalog, _tycoon,
      sqlmesh__main, etc.) when unset. Idempotent — preserves
      user-set values.
    • §5b LM Studio first-class in init wizard. The wizard now
      has a 6-choice LLM prompt (LM Studio / Ollama / OpenAI /
      Anthropic / Gemini / Mistral / Skip). The choice persists to
      ask.llm.provider in tycoon.yml.
  • #22 — Bug: filesystem source CSV ingest defaulted to append
    instead of replace. One-line fix:
    apply_hints(write_disposition="replace") on the piped
    read_csv() / read_parquet() resources in
    _build_filesystem_source. Caught by the new
    test_csv_import_rerun_idempotent offline e2e.
  • #23 — Bug: tycoon data sync failed entire run on any view
    that referenced an unattached catalog (e.g. dbt's tycoon_meta
    ATTACH). Fix: per-table resilience — wrap each copy in
    try/except, accumulate failures into SyncResult.skipped,
    surface the warning in CLI output. The sync proceeds for the
    user-owned tables.
  • #24 — Bug: capture_dlt silently failed for filesystem
    source. DuckDB rejects intra-process opens of the same file
    with mismatched config, and capture ran while dlt's destination
    handle on raw_db was still alive. Fix: ATTACH raw_db from
    inside meta_con as a read-only catalog and query through it
    — single connection, no intra-process collision.

tycoon register llm

# Register a provider (writes tycoon.yml + nao_config.yaml +
# AGENTS.md, seeds exclude_schemas, offers model install).
tycoon register llm lm-studio

# No-arg form refreshes the existing setup against tycoon.yml.
tycoon register llm

# Skip the install prompt (for scripts).
tycoon register llm ollama --skip-install

Replaces the removed tycoon ask init and tycoon ask install-model
commands. Same logic, better namespace.

Provider arg Notes
lm-studio OpenAI-compat at http://localhost:1234/v1; recommended local option
ollama OpenAI-compat at http://localhost:11434/v1; CLI-friendly
openai needs OPENAI_API_KEY
anthropic needs ANTHROPIC_API_KEY
gemini needs GEMINI_API_KEY
mistral needs MISTRAL_API_KEY

Auto-scaffold dbt staging

tycoon data analyze got three improvements:

  • Sentinel + --force. Generated .sql and .yml files now
    start with @generated by tycoon analyze. Re-runs skip files
    where the user has removed the sentinel (took ownership).
    Returns a GenerateResult(generated, skipped) named tuple.
  • Auto-trigger after data sources run <name>. Post-ingest, if
    a dbt project exists and the source isn't already referenced
    anywhere under models/, run analyze. --no-scaffold flag and
    transform.auto_scaffold: false config opt-out.
  • --all flag. Iterate every registered source. Soft-skip
    ones whose raw DB doesn't exist yet.

Local LLM ergonomics

  • Recommended model: Qwen 2.5 Coder 7B Instruct (Q4_K_M, ~4.7
    GB).
    Same model on both runtimes; install hints are
    provider-specific. Researched against current local-LLM
    benchmarks — outperforms Llama 3.1 8B on coding tasks
    (HumanEval 88.4%) at smaller size. Step-up (32B Coder) and
    step-down (Llama 3.2 3B) options listed in the recipe doc.
  • tycoon ask chat fail-fast. No LLM configured / runtime
    unreachable / 0 models loaded → exit 1 with provider-specific
    install hints. No more dead chat UIs.
  • tycoon ask doctor extensions. Probes both LM Studio and
    Ollama for reachability AND model count. FAILs the panel when
    reachable but no models loaded (was previously OK with model
    count of 0, which was misleading).
  • Wizard auto-detect. At init time, probe :1234 and :11434.
    If exactly one runtime is up, suggest it with a 1-keystroke
    confirm. Both up + only one has models → suggest the loaded
    one. Both up + both have models → menu (truly ambiguous).
  • Ollama is now first-class. New _OLLAMA_PRESET mirrors the
    LM Studio one. tycoon register llm ollama generates a proper
    OpenAI-compat config pointed at http://localhost:11434/v1.
  • LM Studio model auto-load. When LM Studio is reachable but
    has chat models downloaded yet 0 loaded in memory, tycoon
    now offers to call lms load <model> automatically rather
    than punting users to the GUI. Fires from both
    tycoon register llm and tycoon ask chat's fail-fast —
    accept the prompt and the model loads in 5-30s, then chat
    continues. Falls back to the GUI hint if lms isn't on
    PATH (or at the standard ~/.cache/lm-studio/bin/lms
    location). Prefers Qwen 2.5 Coder if downloaded; otherwise
    picks the first chat-capable model (embeddings filtered out).
    This is the headline UX win for LM Studio users — the runtime
    separates "downloaded" from "loaded" as user steps, and tycoon
    now bridges that gap automatically.
  • LM Studio probe distinguishes downloaded from loaded. The
    v0.1.5 RC initially used the OpenAI-compat /v1/models
    endpoint, which returned models on disk regardless of memory
    state — making ask doctor falsely report "2 models loaded"
    when nothing was actually in memory. Switched to LM Studio's
    richer /api/v0/models endpoint which exposes per-model
    state: loaded | not-loaded. Falls back to /v1/models for
    older LM Studio versions. _probe_local_llm now takes a
    provider argument so it can route to the right endpoint.

CLI surface stale-string sentinel

A new tests/test_cli_surface.py walks every .py under
src/tycoon/ and rejects any file containing a known-removed
command name or wrong package name. The _STALE_SUBSTRINGS
registry is one-line-extensible after future renames.

Caught and prevented three drift bugs that briefly shipped during
the v0.1.5 cycle and were fixed before the final tag:

  • The auto-generated AGENTS.md header still referenced
    tycoon ask init (which v0.1.5 removed in favor of
    tycoon register llm). Every project's AGENTS.md would have
    carried a stale install instruction.
  • _require_nao's install hint said pip install tycoon[ask]
    instead of the correct pip install 'database-tycoon[ask]'.
    Anyone hitting that error code path got a non-working
    install command.
  • tycoon start --only nao warned users at the removed
    tycoon ask init && tycoon ask sync when no nao_config.yaml
    existed. Users running this in a fresh project would have
    been told to run a non-existent command.

The sentinel test is also a regression guard for the future:
adding a new entry to _STALE_SUBSTRINGS after any rename will
fail any PR that leaves a stale reference behind. Companion
tests assert that removed commands actually fail (not silently
dispatch to something else) and that tycoon --version matches
the published __version__ and pyproject.toml.

Test surface hardening

The new offline + live e2e tests caught the three bug fixes shipped
in this release. Coverage delta:

  • +1 mart layer in csv-import (fct_widget_summary + schema.yml)
    with downstream-aggregate assertions (widget_count, total_quantity,
    min/max).
  • +1 nyc-transit dbt e2e — the existing live e2e now continues
    past raw-DB-exists, runs tycoon data transform run, asserts
    stg_nyc-dot__* tables in the warehouse.
  • +2 idempotency tests (rerun + transform-ingest-transform).
  • +1 sync e2e for the full ingest → transform → sync user
    workflow.
  • +1 register-dbt-external e2e — scaffolds a standalone dbt
    project with a non-default profile name + target, registers,
    runs transform, asserts the model materializes in the
    registered warehouse.
  • +3 dlt write-disposition contract tests (replace / append /
    merge) using in-process resources (no network).
  • +1 sync skip-views unit test.

Net: 378 → 475 passing (+ 48 from the CLI surface sentinel,

  • 8 from the auto-load helpers, + 3 from the LM Studio probe
    fix).

Behavior changes

  • tycoon ask init and tycoon ask install-model removed. Use
    tycoon register llm <provider> instead. The new command is a
    drop-in replacement for the writes side; the no-args form
    refreshes the setup (replacing tycoon ask sync --reinit for
    this purpose).
  • tycoon init chains AI agent setup automatically when the
    user picks an LLM in the wizard AND nao_core is importable.
    Without the [ask] extra, prints a fallback hint pointing at
    pip install 'database-tycoon[ask]' then tycoon register llm.
  • tycoon data sources run <name> auto-scaffolds dbt staging
    models
    (default ON) when no models reference the source yet.
    Opt out per-call with --no-scaffold or per-project with
    transform.auto_scaffold: false.
  • Filesystem source CSV ingest now uses replace semantics
    (was append). Re-running tycoon data sources run files against
    the same files no longer doubles row counts.
  • tycoon data sync continues past broken views. Views that
    reference unattached catalogs are recorded in
    SyncResult.skipped and warned about; the sync still copies
    every other table.

Removed templates from default surface

weather-station and github-analytics are demoted but not
deleted — they stay on disk so tycoon init --template <name>
still works for anyone scripted against them, but they no longer
appear in --list-templates output, the docs landing pages, or
the CI smoke matrix. The featured surface is now csv-import
(offline) and nyc-transit (live).

Hygiene

  • tests/conftest.py:_stub_local_llm_probe (autouse fixture)
    neutralizes LM Studio / Ollama port probes during tests so the
    suite doesn't behave differently on devs running either runtime
    locally. Tests that exercise auto-detection re-patch as needed.
  • Templates that declare dbt_project_dir but don't ship one
    now get one scaffolded
    during tycoon init --template <name>.
    Previously a silent gap — only csv-import had a working dbt
    project on init.
  • Per-package dependency reference doc. New
    docs/reference/dependencies.md lists every pin in
    pyproject.toml (base + [server] + [dagster] + [ask] +
    [docs] + dev) with what each package does at runtime and an
    install-footprint summary. The audit also flagged two redundant
    pins — websockets==16.0 in [server] (pulled transitively by
    uvicorn[standard]) and ibis-framework[duckdb]==12.0.0 in
    [ask] (pulled transitively by nao-core) — both queued for
    removal in v0.1.6 to keep the install footprint honest.

Out of scope

  • #14 (v0.2.0 init redesign — hard breaking change, kept
    separate.)