A module can adopt a public interface by matching interface rules in tach.toml.

How does it work?

When Tach is checking imports from a module with a public interface, it will verify that the import matches one of the expose patterns. This prevents other modules from becoming coupled to implementation details, and makes future changes easier.

Example

Given modules called ‘core’ and ‘domain’, we may have tach.toml contents like this:

[[modules]]
path = "domain"
depends_on = [
    { path = "core" }
]

[[modules]]
path = "core"
depends_on = []

[[interfaces]]
expose = ["get_data"]
from = ["core"]

Then, in domain.py, we may have:

from core.main import DataModel  # This import fails

DataModel.objects.all()

This import would fail tach check with the following error:

❌ domain.py[L1]: Module 'core' has a public interface. Only imports from the public interface of this module are allowed. The import 'core.main.DataModel' (in module 'parsing') is not public.

In this case, there is a public interface defined in tach.toml which includes a service method to use instead.

from core import get_data  # This import is OK

get_data()

tach check will now pass!

✅ All modules validated!