Skip to content

Recommended Presets

Four presets to start from, organised by project shape.

CLI tool / script

Small startup time matters; concurrency is rare.

[project]
name = "mytool"
version = "0.1.0"
[python]
target = "3.13"
free-threaded = false
[emit]
class-default = "dataclass"
format = true
[strictness]
no-implicit-any = true
unused-import = "error"
exhaustive-match = "error"
auto-memoise = false # caches extend lifetimes — not worth it for CLIs
auto-gather = false
auto-parallel = false
pgo-memoise = false
[env]
required = [] # most CLIs don't have build-time required vars
[dependencies]
click = ">=8" # or argparse from stdlib

Use lazy import for heavyweight dependencies (pandas, torch). Use comptime let for tool metadata (version string baked at build).

HTTP API / web service

Concurrency dominates; data crosses trust boundaries.

[project]
name = "myapi"
version = "0.1.0"
[python]
target = "3.13"
free-threaded = false
[emit]
class-default = "dataclass" # internal types
format = true
[strictness]
no-implicit-any = true
unused-import = "error"
exhaustive-match = "error"
unintrospectable-dependency = "error" # CI-gate: every dep must be checkable
auto-memoise = false
auto-gather = false # use explicit `gather:` blocks
auto-parallel = false
pgo-memoise = false
[checker]
external = "ty" # type-check emitted Python against typeshed
[env]
required = ["DATABASE_URL", "API_KEY"]
[dependencies]
fastapi = ">=0.110"
uvicorn = ">=0.27"
pydantic = ">=2"
sqlalchemy = ">=2"
httpx = ">=0.27"
[dev-dependencies]
pytest = ">=8"
pytest-asyncio = ">=0.23"

Use model for request / response bodies (Pydantic validation at the boundary). Use class for internal types. Use gather: for fan-out reads. Use go for fire-and-forget metrics / logging.

Data processing / numerical

Heavy compute on large collections; free-threaded mode helps.

[project]
name = "mypipeline"
version = "0.1.0"
[python]
target = "3.14t" # the free-threaded build
free-threaded = true # opt into threading parallelism
[emit]
class-default = "dataclass"
format = true
[strictness]
no-implicit-any = true
unused-import = "error"
exhaustive-match = "error"
auto-memoise = false
auto-gather = false
auto-parallel = true # rewrite pure comprehensions to thread-pool map
parallel-min-size = 64
pgo-memoise = true # cache hot pure helpers from profile data
pgo-min-calls = 100
[dependencies]
numpy = ">=2"
polars = ">=1"

Mark pure helpers with @pure. After the first profiling run, pgo-memoise will cache the hottest ones automatically. Use lazy import to defer numpy / polars startup for short-running modes.

Library

Strict; no PyPI runtime overhead.

[project]
name = "mylib"
version = "0.1.0"
[python]
target = "3.13"
free-threaded = false
[emit]
class-default = "dataclass"
format = true
[strictness]
no-implicit-any = true
unused-import = "error"
exhaustive-match = "error"
unintrospectable-dependency = "error" # a published lib must check every dep
auto-memoise = false
auto-gather = false
auto-parallel = false
pgo-memoise = false
[checker]
external = "ty" # catch stdlib / C-extension misuse before release
[dependencies]
# Keep this minimal — library users inherit your deps.
[dev-dependencies]
pytest = ">=8"
pytest-cov = ">=4"

Make sure to ship .dty stubs for the public API alongside the source, so consumers see the strict Typhon types when they pull your library through a .pyi. Run tyc check --stubs and tyc stubtest in CI.

Migration project

A project that’s progressively rewriting Python → Typhon.

[project]
name = "myapp"
[python]
target = "3.13"
[emit]
class-default = "dataclass"
format = true
[strictness]
no-implicit-any = true
unused-import = "warn" # softer during the migration
exhaustive-match = "warn"
auto-memoise = false
auto-gather = false
auto-parallel = false
pgo-memoise = false
[env]
required = ["DATABASE_URL"]

Once migration stabilises, raise unused-import and exhaustive-match back to "error".

Where next