Simple example
Start with TypeSpec models that represent the runtime shape you want every target to agree on. Use Typra samples as evidence for generated examples and conformance tests; samples are not runtime defaults.
import "@typra/emitter";import "@typespec/http";
using TypeSpec.Http;
namespace Todo.Contracts;
model TodoList { name: string; items: TodoItem[];}
model TodoItem { @sample(#{ id: "todo-1" }) id: string;
@sample(#{ title: "Write the contract" }) title: string;
state: TodoState;}
union TodoState { open: "open"; done: "done"; archived: "archived";}Add callable contracts with TypeSpec-native interface and op declarations. Attach @vector cases when behavior should be verified across generated runtimes.
model RenderRequest { item: TodoItem;}
model RenderResult { text: string;}
const RenderVectors = #[ #{ name: "open-item", stage: "render", input: #{ request: #{ item: #{ id: "todo-1", title: "Write the contract", state: "open" } } }, expected: #{ text: "- [ ] Write the contract" } }];
interface TodoRenderer { @vector(RenderVectors) render(request: RenderRequest): RenderResult;}When you need transport projection, layer official TypeSpec HTTP decorators on the callable operation. Typra consumes that HTTP metadata; it does not invent a parallel routing vocabulary.
@route("/todos")interface TodoApi { @get @route("/{id}") read(@path id: string): TodoItem;}Configure Typra with the root model and the targets you want to emit:
emit: - "@typra/emitter"
options: "@typra/emitter": emitter-output-dir: "{cwd}/generated" root-object: "Todo.Contracts.TodoList" deterministic-output: true emit-targets: - type: TypeScript output-dir: "generated/typescript" test-dir: "generated/typescript/tests" import-path: "../index" - type: Python output-dir: "generated/python/todo_contracts" test-dir: "generated/python/tests" import-path: "todo_contracts" outputs: - kind: server provider: fastapi - type: Markdown output-dir: "generated/markdown"Compile with TypeSpec:
npx tsp compile ./main.tsp --config ./tspconfig.yamlTypra emits target code, generated tests when test-dir is set, Markdown reference output when requested, optional contributor outputs such as FastAPI route scaffolds, and metadata that can be compared in CI.
generated\ typescript\ python\ todo_contracts\ fastapi_routes.py markdown\ json-ast\model.json .typra-generated\manifest.json .typra-generated\report.jsonThe important split is ownership: TypeSpec owns the durable contract, Typra owns repeatable generated surfaces, and your product owns any runtime behavior around those surfaces.