v0.1.5
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 initchains 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-keystrokeDetected 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 dbtandtycoon register warehouse— point
tycoon at an external resource, record the linkage in
tycoon.yml. Removedtycoon ask initand
tycoon ask install-model; theasknamespace is now reserved
for analytics endpoints (chat, sync, context, doctor, skills,
mcp). Read-only LLM probing stays inask doctor. -
Auto-scaffold dbt staging from dlt schema. The
tycoon data analyzecommand (which has existed since v0.1.1)
is now sentinel-protected, auto-triggered after
tycoon data sources run, and supports--allfor multi-source
scaffolding. The user-visible flow collapses from
init → ingest → analyze → transformto just
init → ingest → transformfor the happy path. Re-runs preserve
hand-edits via the@generated by tycoon analyzesentinel; pass
--forceto override. -
Three real bugs caught and fixed. The new e2e coverage
surfaced #22 (filesystem CSV ingest defaulted to append, not
replace), #23 (data syncfailed 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_schemasdefaults.tycoon register llm
seedsask.exclude_schemaswith 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.providerin tycoon.yml.
- §3 smart
- #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_idempotentoffline e2e. - #23 — Bug:
tycoon data syncfailed entire run on any view
that referenced an unattached catalog (e.g. dbt'stycoon_meta
ATTACH). Fix: per-table resilience — wrap each copy in
try/except, accumulate failures intoSyncResult.skipped,
surface the warning in CLI output. The sync proceeds for the
user-owned tables. - #24 — Bug:
capture_dltsilently 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: ATTACHraw_dbfrom
insidemeta_conas 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-installReplaces 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.sqland.ymlfiles now
start with@generated by tycoon analyze. Re-runs skip files
where the user has removed the sentinel (took ownership).
Returns aGenerateResult(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 undermodels/, run analyze.--no-scaffoldflag and
transform.auto_scaffold: falseconfig opt-out. --allflag. 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 chatfail-fast. No LLM configured / runtime
unreachable / 0 models loaded → exit 1 with provider-specific
install hints. No more dead chat UIs.tycoon ask doctorextensions. 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
:1234and: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_PRESETmirrors the
LM Studio one.tycoon register llm ollamagenerates a proper
OpenAI-compat config pointed athttp://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 calllms load <model>automatically rather
than punting users to the GUI. Fires from both
tycoon register llmandtycoon ask chat's fail-fast —
accept the prompt and the model loads in 5-30s, then chat
continues. Falls back to the GUI hint iflmsisn'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 — makingask doctorfalsely report "2 models loaded"
when nothing was actually in memory. Switched to LM Studio's
richer/api/v0/modelsendpoint which exposes per-model
state: loaded | not-loaded. Falls back to/v1/modelsfor
older LM Studio versions._probe_local_llmnow takes a
providerargument 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.mdheader 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 saidpip install tycoon[ask]
instead of the correctpip install 'database-tycoon[ask]'.
Anyone hitting that error code path got a non-working
install command.tycoon start --only naowarned users at the removed
tycoon ask init && tycoon ask syncwhen nonao_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, runstycoon 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 initandtycoon ask install-modelremoved. 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 (replacingtycoon ask sync --reinitfor
this purpose).tycoon initchains AI agent setup automatically when the
user picks an LLM in the wizard ANDnao_coreis importable.
Without the[ask]extra, prints a fallback hint pointing at
pip install 'database-tycoon[ask]'thentycoon 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-scaffoldor per-project with
transform.auto_scaffold: false.- Filesystem source CSV ingest now uses replace semantics
(was append). Re-runningtycoon data sources run filesagainst
the same files no longer doubles row counts. tycoon data synccontinues past broken views. Views that
reference unattached catalogs are recorded in
SyncResult.skippedand 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_dirbut don't ship one
now get one scaffolded duringtycoon init --template <name>.
Previously a silent gap — onlycsv-importhad a working dbt
project on init. - Per-package dependency reference doc. New
docs/reference/dependencies.mdlists 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.0in[server](pulled transitively by
uvicorn[standard]) andibis-framework[duckdb]==12.0.0in
[ask](pulled transitively bynao-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.)