Project Layout
tyc init NAME scaffolds a fresh Typhon project. This page describes the resulting layout, what each file is for, and the conventions you should follow as the project grows.
What tyc init produces
Directoryhello/
- typhon.toml Project configuration
Directorysrc/ Source directory (
.tyfiles)- main.ty Entry point
Directorytests/ Test directory (Python or
.tytests)- …
- .gitignore Excludes
build/andtarget/by default
The shape is intentionally close to a small Python project so it’s familiar.
typhon.toml
The single configuration file every tyc subcommand reads. Default contents:
[project]name = "hello"version = "0.1.0"src = "src"out = "build"
[python]target = "3.13"
[emit]class-default = "dataclass"format = true
[strictness]no-implicit-any = trueunused-import = "error"exhaustive-match = "error"Full reference: Configuration.
Common edits
- Add dependencies with
tyc add— writes[dependencies]and[dev-dependencies]sections. - Pin a Python target.
target = "3.14"to opt into newer syntax;free-threaded = trueto opt into the threading parallelism emit paths (requires thetbuild). - Tune strictness. Lower
unused-importto"warn"during refactors; raiseauto-memoisetotrueif you want pure-function caching project-wide.
src/
The source directory. Every .ty file here is compiled into a matching .py in build/ when you run tyc build. Module structure mirrors the directory layout — src/foo/bar.ty becomes build/foo/bar.py and is importable as foo.bar.
What goes here
.tysource files..dtystubs for third-party libraries (see Writing .dty stubs).- Plain
.pyfiles when you can’t or don’t want to rewrite them — they pass through untouched.
What doesn’t go here
- Build artefacts (
build/). - Editor files (
.vscode/,.idea/). - Generated
typhon_runtime/— that lands inbuild/, not insrc/.
tests/
Test files. Typhon has no opinion on which test framework you use; pytest works perfectly against the emitted Python.
A common layout:
Directorytests/
- conftest.py pytest fixtures (plain Python)
- test_users.py Tests against build/users.py
- test_users.ty Or write tests in Typhon
When you write tests in .ty, they compile to .py like any other source file. You can run pytest against the emitted Python:
tyc buildpytest build/tests/Or use tyc run with an entry point that hosts your test runner.
build/
The output directory (configurable via [project] out). Created by tyc build; safe to delete at any time. Contains:
Directorybuild/
- main.py Emitted from src/main.ty
- main.py.map Source map: out_line → ty_line
Directorytyphon_runtime/ Generated runtime helpers (only if used)
- init .py
- tasks.py Strong-ref task registry for
go - result.py Ok / Err / Result classes
- lazy.py
lazy_lethelper
typhon_runtime/
A small, generated Python module with the helpers Typhon programs need: the Result ADT (Ok / Err), the lazy_let thread-safe one-shot helper, the tasks.spawn strong-ref registry. It is not on PyPI — it is generated source the build owns. If you don’t use Result, lazy let, or go, the module isn’t emitted at all.
This is by design: production servers run the emitted Python plus this small helper. There is no Typhon package to install anywhere.
.py.map files
Source maps (v2 format), per-statement (out_line → ty_line) tables. Used by:
tyc traceto map a Python traceback back to.tysource.- The LSP for cross-file go-to-definition across the
.ty/.pyboundary.
Safe to delete; they regenerate.
Conventions as projects grow
Module organisation
The same conventions as a Python package: small, focused modules; one class per file (or a few related ones); domain logic in src/<package>/<module>.ty. Use __init__.ty for package roots — tyc treats it like Python’s __init__.py.
Stubs go beside the project, not inside src/
A common pattern:
Directorymyproj/
- typhon.toml
Directorysrc/ Application source (compiled to
build/)- …
Directorystubs/
.dtystubs for untyped third-party libraries- redis.dty
- kafka.dty
tyc check --stubs finds .dty files anywhere in the project tree.
Multiple entry points
Place each entry point as its own .ty file at the root of src/:
Directorysrc/
- api.ty Web server entry
- cli.ty CLI tool entry
- worker.ty Background worker entry
Directorylib/ Shared modules
- users.ty
- db.ty
Run a specific one with tyc run --entry api.py. Or wire each in your packaging tool (pyproject.toml [project.scripts], a Dockerfile, etc.).
Mixed .ty and .py
Plain .py files in src/ are copied to build/ unchanged. They can import from emitted modules, and vice versa. Useful for:
- Files you haven’t migrated yet.
- Generated code (e.g. protobuf bindings).
- Things that genuinely can’t be expressed in Typhon (or aren’t worth the rewrite).
The checker treats imports from a plain .py as if they crossed an unsafe: boundary unless an authored .dty overrides them.
What’s in version control
# .gitignore (created by `tyc init`)build/target/*.py.map__pycache__/.pytest_cache/- Yes commit:
typhon.toml,src/,tests/,stubs/,editors/configs. - No commit:
build/(deterministic fromsrc/),target/(Rust artefacts if you’re buildingtychere too),*.py.map.
typhon-profile.json (the PGO profile) is a judgement call. Commit it if you want CI to use it; gitignore it if it’s developer-local.
Multi-project monorepos
For monorepos with multiple Typhon projects, each project gets its own typhon.toml. tyc looks for the nearest typhon.toml up the directory tree, so subcommands “just work” from inside any project’s src/.
The compiler does not yet have a workspace concept (cross-project shared dependencies, common config inheritance). For now, duplicate typhon.toml across projects and use a top-level Makefile / justfile to drive builds.
Where next
- Your First Real Program — moving past
Hello, world. - Editor Setup — VS Code, Neovim, Helix.
typhon.tomlOverview — every key, every default.