Skip to content

tyc build

tyc build [PATH] [--out DIR] [--no-format] [--check] [--no-sync] [--with-ty] [--optimise]

Runs the full compilation pipeline and writes the emitted Python to the output directory (default build/, configurable via [project] out).

Examples

Terminal window
tyc build # full project → build/
tyc build --out dist/ # → dist/ instead
tyc build --no-format # skip the ruff format post-process
tyc build --check # dry-run: list every file that would be written
tyc build -O # apply [optimise] level = 1 for this invocation
tyc build --no-sync # skip `uv sync` (also TYC_NO_SYNC=1); pyproject.toml is still merged
tyc build --with-ty # then run Astral's `ty` over the emitted Python

What it produces

For a project with src/main.ty and src/users.ty:

build/
├── main.py
├── users.py
├── .sourcemaps/
│ ├── main.py.map # source map v2 (under .sourcemaps/ since v0.6.1)
│ └── users.py.map
└── typhon_runtime/ # only if Result / go / lazy let / freeze let / as! / auto-parallel are used
├── __init__.py
├── result.py
├── tasks.py
├── lazy.py
├── parallel.py
├── freeze.py
├── cast.py
├── traceback.py
└── stdlib.py

And, if you have .dty stubs:

build/
├── ... (above)
└── *.pyi # PEP 561 stubs alongside emitted .py

The pipeline stages

  1. Lex + parse (tyc-syntax).
  2. Resolve (tyc-resolve) — symbol tables, scopes, let/mut classification.
  3. Type-check (tyc-types) — narrowing, signature compatibility, exhaustiveness.
  4. Analyse (tyc-analyse) — purity, async, comptime, auto-gather.
  5. Desugar (tyc-desugar) — merge impl blocks, expand ?, lower gather: / go / lazy, evaluate comptime.
  6. Emit (tyc-emit) — hand-written printer produces .py + .py.map.
  7. Format (tyc-format) — post-process through ruff format when [emit] format = true.

Each stage is a Salsa query; on incremental rebuilds, only invalidated outputs are recomputed.

Flags

FlagEffect
--out DIR (-o)Override the [project] out directory. Relative paths resolve against the project root.
--no-formatSkip the ruff format post-process.
--checkDry-run mode. The full pipeline still runs (so type errors continue to surface), but no files are written — instead, every file that would be created or overwritten is listed. Useful for previewing the effect of a class-default or skip-decoration-bases change before committing to disk.
--no-syncSkip the uv sync step; pyproject.toml is still merged so the next regular build picks the manifest up. Also honoured via TYC_NO_SYNC=1.
--with-tyAfter a successful build, run Astral’s ty over the emitted Python as a typeshed-backed second-stage check — the same behaviour as [checker] external = "ty", for one invocation. ty errors fail the build. Requires ty on PATH.
--optimise / -O (alias --optimize)Apply [optimise] level = 1 for this invocation — flips the default of auto-memoise, auto-gather, auto-parallel, and pgo-memoise to on. Overrides a config level = 0, but an explicit [strictness] entry for any of those knobs still wins.

.py files alongside .ty

Plain .py files in src/ are copied verbatim into the build output (skipping __pycache__/, tests/, .venv/, and dotfiles). This is the recommended escape hatch when a class can’t be expressed cleanly in Typhon — write it in Python, drop it next to your .ty files, and the relative import keeps working at runtime. A relative .py import that resolves to a file outside src/ fires tyc::orphan_py_import so the missing-at-runtime case is caught at build time.

When the build fails

If any error-severity diagnostic fires during check or analyse, the build does not produce output. The diagnostics are emitted to stderr and the process exits 1.

You can run tyc check first to fail-fast in CI without producing partial artefacts.

What’s not in build/

  • Python bytecode (*.pyc, __pycache__/) — created by Python at runtime, not by tyc build.
  • Cargo artefacts (target/) — those are from building tyc itself, kept in the tyc/ subdirectory.
  • Editor or test caches — tyc doesn’t manage those.

Safe to delete build/ at any time; it regenerates.

Incremental rebuilds

Salsa caches every stage’s output. If you change one function in one file, the rebuild typically touches only that file’s emit, not the whole project. The cost is roughly proportional to the change size.

Where next

  • tyc run — execute a Typhon program (in-process VM by default, --compile for build-then-exec).
  • tyc check — type-check without emit.
  • Lowering Overview — what each construct compiles to.