Code generation¶
tuvl codegen writes the parts of a project that follow mechanically from its YAML, so you only
write the parts that need judgement. It is deterministic: no model is called, and tuvl never
writes function bodies.
tuvl codegen # all workflows
tuvl codegen triage_ticket # one workflow's stubs, prompts and tests
tuvl codegen --check # write nothing; exit 1 if anything would change (the CI gate)
What it generates¶
| Output | Rule |
|---|---|
agents/_generated/schemas.py |
<Id>In / <Id>Out models per agent (per-signal variants and <Id>Signal), plus <Workflow>Input and <Workflow>End. Never hand-edited |
agents/<run>.py |
A stub for each code agent when missing; when present, a merge that refreshes the decorator, signature and docstring and keeps your body |
artifacts/<name>.md |
A prompt placeholder for an artifact:// that an llm or loop agent references and that does not exist yet |
decide agents |
A block with neither rules nor a model gets one never-matching rule per enum value, each marked # TODO |
tests/<workflow>/<example>.yaml |
A test per tuvl-example block in the spec. Hand-written tests are never touched |
The loop for a code agent¶
- Declare the agent in the workflow YAML (or add a step in Insight): its
run,inputs,outputs. -
Run
tuvl codegen. You get a typed stub:from __future__ import annotations from tuvl import Ctx, agent from agents._generated.schemas import ScoreTicketIn, ScoreTicketOut @agent("score_ticket") async def score_ticket(inp: ScoreTicketIn, ctx: Ctx) -> ScoreTicketOut: """Score how urgent a ticket is.""" raise NotImplementedError("score_ticket") -
Replace the
raisewith your logic. Everything above the body is owned by codegen. - Change the contract later (rename an input, add an output) and run
tuvl codegenagain: the signature and types update, and your body stays.
In Insight, choosing the code engine for an agent offers ⌘ Generate stub, which runs the same
step, and saving the Python file normalizes the decorator and signature through codegen.
Keeping it honest in CI¶
Generated files are committed, so a contract change that was not regenerated is a failing build:
tuvl codegen --check
It is one step of the CI gate, alongside tuvl validate
--strict, tuvl lock --check and tuvl test --strict. Run tuvl codegen locally and commit the result.
Notes¶
- Don't edit
agents/_generated/. It is rewritten on every run. - One
@agent("run")per contract. If two agents share arunwith different contracts, codegen warns and types the function asAny. - Coding agents can run it through the dev MCP server:
codegen(a dry run) always, andcodegen_writewith--allow-write. See Build with Coding Agents.
See also¶
- Spec-driven development — where codegen sits in the flow
- Project structure
- CLI reference