Repository navigation
v0.2.2 — project-local environments
v0.2.2
Released: 2026-10-09
Headline: project-local environments.
Two problems shaped this release. Adding a source could succeed while its
dependencies never got installed, so the first run failed on a missing
import with nothing having warned you. And a filesystem load that found
nothing to read could still empty a table that already held rows, then
report "load complete".
Every project now gets its own uv-managed environment, with source code
and dependencies tracked inside the project. A load that finds nothing
leaves your table alone, and a run that loaded zero rows is flagged
instead of reading as a healthy sync. Around those two: MotherDuck
warehouse targets work end to end, --max-records caps every source
type, and saving tycoon.yml keeps your comments.
Landed
Each project gets its own environment
tycoon initbuilds a project-local.venv. It seeds a
pyproject.tomland runsuv syncright after scaffolding, so there is
no separatetycoon setupstep to forget.tycoon setupand
tycoon doctor --fixbuild the same way, andtycoon init --no-venv
opts out.- Source code and dependencies live in the project. A catalog source
downloads into<project>/.tycoon/sources/rather than one
~/.tycoon/sources/shared by every project on the machine. Its
dependencies go into the project'spyproject.tomlwithuv add, so
deleting.venvand runninguv syncrebuilds the same environment,
source dependencies included. When an install fails, you see uv's own
error, so a version conflict and a timeout no longer look the same. - Every source's requirements get installed, not just the first one's.
dlt initwrites a sources directory's sharedrequirements.txtonly
once, so a second catalog source's dependencies were never recorded or
installed, and its first run failed on an import. The file now holds
every source's requirements. tycoon data sources migrate <type>copies a source installed in the
old shared location into the project, along with its requirements, and
installs them. It never overwrites a directory that already holds your
files.tycoon data sources runpoints at it when it finds a source
sitting in the old directory, instead of reporting "not installed".- You're told where an install is going. In a project with a hand-made
.venvbut nopyproject.toml,sources addnow warns that a dlt extra
will go into the shared environment and names that destination in the
prompt, instead of installing there silently. - A failed download says why.
sources addprinted only "Failed to
download" whether you were offline or had mistyped the source name. It
now shows dlt's own error line, and the retry hint names a command that
exists. tycoon doctortells you which model a project is on. It reports
whether the project has its own.venvand whether tycoon is actually
running from it. The same warning fires before a run or an install falls
back to the old shared behaviour. Nothing forces a migration.--no-promptinstalls a source's dependencies.
tycoon data sources add <type> --no-promptused to register the source
without downloading or installing anything, because the install step was
skipped along with the prompt. It now installs, and a failed install
rolls thetycoon.ymlchange back.
A load that finds nothing leaves your data alone
- A glob that matches no local files no longer empties the table.
Filesystem sources load withreplace, so a rerun whose glob matched
nothing (a typo, or a folder that emptied out) used to truncate the
table and report success. That resource is now left out of the run with
a warning, and the other resources in the source still load. If nothing
matched at all, the run exits 0 with "nothing to load". - A
paththat names a single file loads that file. Answering
data/sales.csvat the path prompt used to produce a source that loaded
zero rows, every time. A file path, plain orfile://, now reads as its
directory plus that file name. Afile_globset alongside a file path
is an error, since it could never match. - Zero-row runs are flagged. The
run_completedledger event carries
zero_rowsand awarningslist. A run is flagged when areplace
resource loaded zero rows, even if others loaded some, or when a glob
matched nothing. An append, merge or incremental run with no new records
is a normal sync and is not flagged.tycoon data statusmeasures
freshness from the last run that loaded something, and
tycoon data historymarks a flagged run with a yellow!. --fail-on-emptyondata sources run,data sources run-alland
data run-allturns those cases into a failure: the command exits 1 with
an error naming the table, and the ledger recordsrun_failed. Use it on
a schedule, where an exit code is the only thing anyone sees.
Fixes
- MotherDuck warehouses work with
data query,data schemaand
data clean. Withdatabase.warehouse: md:<name>intycoon.yml,
tycoon used to look for a local file of that name, anddata clean --all
could delete a local file calledmd:<name>_raw. Anmd:target now
goes to DuckDB unchanged. Commands that still need a local raw database,
such asdata sources run, stop with a clear error instead. --max-recordscapsfilesystem,rest_apiandsql_database
sources. These printed the cap and then loaded every row.- Saving
tycoon.ymlkeeps your comments, blank lines and indentation.
Only the values tycoon changes are rewritten, and a${ENV}reference
stays a reference.tycoon registernow saves the same way. - Rill source files use relative paths. Generated Rill sources used to
carry the absolute path to the Parquet export, which broke on every
other clone and in CI. tycoon citybuilds faster from cold. A coldcity.jsonon an
87-object catalog dropped from 43.6s to 10.3s, with identical lineage.- A quoted
motherduck_tokenis masked in printed errors.
motherduck_token='...'used to pass through the redaction with the
token intact. - The
data run-alldocs list the options the command has. The page
described flags that didn't exist.
Upgrading from 0.2.1
- An existing project keeps working as it did. Until it has its own
.venv, sources stay in the shared~/.tycoon/sources/and installs go
where they went before.tycoon doctorwarns about this. To move a
project over, runtycoon setup, then
tycoon data sources migrate <type>for each catalog source it uses. --no-promptnow installs dependencies. A CI job that ran
tycoon data sources add ... --no-promptand then installed packages
itself can drop its own install step. If you relied on--no-prompt
not touching the environment, that has changed.tycoon data statusmay show an older Last Sync. A zero-row run no
longer counts as a sync, so a source whose recent runs loaded nothing
shows the last run that did. Ledger events written before 0.2.2 read
back as not zero-row.- A filesystem run that matches nothing exits 0 with "nothing to
load", not "load complete", and leaves the table as it was. A script
that parsed the old message needs updating. Add--fail-on-emptyif
you want it to fail instead. - A negative
--max-recordsis now a usage error. - A MotherDuck query is not opened read-only. DuckDB supports
read_onlyonly for local files, so whatdata querycan change on
MotherDuck depends on your token's permissions.
Known limitations
- The legacy-table warning does not reach multi-resource sources.
Migrating a flat filesystem source to theresources:shape leaves the
old generic table behind without a warning. Tracked in
#244. - The city is a plan, not yet a simulation. Vehicles and guests are
simulated but not drawn, and coverage milestones are not surfaced. The
fixes (#250, #251) and the renderer's CI gate (#256, #252) move to
0.2.3. - Remote object storage is still unsupported.
s3://,gs://and
az://are recognised only well enough to be skipped by the local-glob
check.
For contributors
- The build is reproducible. hatchling is pinned in
[build-system] requires, since an unpinned upgrade changed the wheel's
metadata version between 0.1.11 and 0.2.0 and the publisher rejected it.
The sdist now holdssrc/and the package metadata only, down from
2.9 MB to 523 KB. - The release docs match the publish workflow.
docs/publishing-to-pypi.mddescribes the four jobs that actually run
and the fix-forward-and-re-tag procedure for a failed publish. - A root
CLAUDE.mdpoints coding agents atCONTRIBUTING.md, the PR
template and the writing-style skill. It holds no rules of its own. - Merging into a release branch is documented. CONTRIBUTING now covers
merge commits, pinning a merge to the reviewed head, merging stacked PRs
and checking a CHANGELOG after a rebase. - Upgrade safety is part of the contributor guide. CONTRIBUTING
covers testing that a change doesn't break an existing project, and the
PR template asks for a short mental model of each change: input,
change, outcome. - Project tracking moved to GitHub. Issues, per-release milestones and
the public Tycoon CLI project board
are the record of what's planned. The Jira board is no longer updated.
The decision is in Discussion #353.
What's next
0.2.3 picks up the city stack (#248 through #256): the renderer's tests
in the default pytest run, the vehicle, guest and achievements fixes,
and a CI gate for the web front end. It also brings #260, which creates a
new dbt project inside the tycoon project instead of next to it.