One runtime, one contract for functions and AI. Compose deterministic functions, reasoning agents, tools, and live supervision into a single governed flow — declared in YAML, observable and secured by default.
No orchestration framework to assemble, nothing to glue. The engine ships the whole surface — deterministic functions and governed AI — as a closed set of composable primitives, each mounted as a live API route at startup.
The backbone of every workflow: run your code, branch on data, call APIs and MCP tools, do CRUD on Postgres, pause for a human, and shape the response.
Bring a model in for a single governed call, or a bounded tool-loop that decides for itself — placed only on the steps that genuinely need judgment.
Most of a workflow is deterministic, and tuvl treats that as first-class. Seven step kinds do the actual work — fast, testable, and free of any token cost.
One @node per file, typed context in and out. Drop in any logic the declarative kinds don't cover.
A binary condition: or a multi-way match: switch — routing decided by data, never by a prompt.
Templated URL, headers, and body; extract JSON straight into context with declared paths.
Create / get / list / update / delete on your Postgres models — IAM-scoped, no query code.
Map context into the terminal HTTP response — the workflow's public contract, declared.
Suspend on a human decision and resume exactly where it stopped — replay-proof, state intact.
Declared model, prompt, and structured output; deterministic routing on the result. Every model it touches must be allow-listed in spec.context.models — enforced at load, or it fails to start.
The model picks declared tools, observes results, and re-decides — until it emits an author-defined outcome or a reserved exit. Guided by steering and per-agent skills, bounded by max_iterations + token_budget.
Autonomy is bounded by construction: the agent chooses which tool to call, but never what tools exist. Every tool is a real, governed step — nothing is a free-floating function.
Any Functional / APICall / ModelOp becomes a tool by wiring it to the agent. A mandatory description tells the model when to call it.
Connect any MCP server over stdio or SSE — GitHub, filesystems, internal services — and its tools become callable steps in the same flow.
The toolset is a fixed, author-declared set. Results return to the agent; a tool merges into shared context only with writes_context.
Add one off-spine Supervisor node per workflow. It watches every AutonomousAgent run out-of-band and intervenes cooperatively — at the turn boundary, never mid-call, so no state is torn.
Double-click it: pick the judge model from a dropdown, set the criteria inline or as a scoped .md policy you edit in place, choose the on_violation action, and add deterministic rules. Every field serializes to spec.supervisor — no hand-written YAML.
tool_repeated, budget_fraction, iteration_reached — cheap guardrails, no LLM.
A judge model checks the run against a natural-language policy — or a scoped .md — and flags violations.
Steer a drifting run back, pause it, or exit cleanly via aborted. Every action logged and streamed.
Non-deterministic output needs deterministic verdicts and full visibility. tuvl builds both in — one judge core, and OpenTelemetry from the first span.
Scorecard{passed, reason} — grade a workflow in CI tests, live inside the Supervisor, or on a replayed run from the Insight portal. The same verdict, everywhere.gen_ai.* semantic-convention spans — model, tokens, latency — exported via TUVL_OTLP_ENDPOINT to Grafana, Datadog, or Honeycomb.iteration / tool_call / outcome / supervisor frames live over SSE and gRPC — not one opaque step.secure: true masked on every stream snapshot — REST, SSE, gRPC alike.Because deterministic functions carry most of the flow and every reasoning loop is capped, you spend tokens only where they earn it — a direct result of the design, not a feature to tune.
max_iterations + token_budget bound each run; the Supervisor kills a runaway before it burns the budget.agent:observe / agent:control scopes for the operator API. iam:admin is the only bypass.spec.context.models → PermissionError. Unmapped routes raise. No hidden behavior slips in.