Skip to content

How Tenchi works

Tenchi has one architecture: typed contracts at the boundary, plain use cases at the center, and explicit dependency wiring around them. Five pieces are enough to serve an HTTP API. Learn them once; everything else in Tenchi is another entrypoint to the same pieces.

Contract

A frozen declaration of one HTTP operation: method, path, validated inputs, successful responses, and the application errors callers may observe. A contract contains no handler logic.

Route

A binding between a contract and a use case. route() inspects the use-case signature immediately, so a mismatched parameter name or annotation fails while the application is composed rather than on the first request.

Use case

A plain async function that implements one application action. Its parameters are named boundary values such as request, params, query, headers, and context. It never receives a Starlette request, so the same function runs unchanged from HTTP, tests, scripts, and workers.

Port and adapter

A port is an interface the application needs, declared with typing.Protocol. The feature owns the port; infrastructure supplies an adapter that implements it. A SQL repository and a memory test double are both adapters for the same port, so the application stays independent of any database driver, HTTP SDK, cache, or queue.

Context

A frozen dataclass carrying the dependencies and verified identity available to a use case. The application constructs it explicitly at the server composition root. Tenchi has no service locator or dependency-injection container.

Boundary flow

HTTP request
  -> route match
  -> request id and context factory / request scope
  -> boundary hooks
  -> size, media-type, and Pydantic input validation
  -> plain use case
  -> response presenter and header projector
  -> Pydantic response validation
  -> HTTP response

The typed client runs the complementary checks: it serializes inputs from the same contract and validates the status, media type, body, headers, and declared application errors returned by a server.

Optional extensions

None of the following is required to define and serve an HTTP API. Each one gives an existing use case another entrypoint or another rule, and each has its own guide.

The key tradeoff

Tenchi asks for more structure than a one-file microframework example. In return, an endpoint's validation, client behavior, OpenAPI, compatibility policy, and application boundary do not become separate models as the service grows.