execute(ctx) — and returns whatever that function returns. Everything you need at runtime arrives on the ctx object: input, secrets, LLM access, HTTP, datastores, and more.
Here is a complete, minimal workflow:
The repo ships this as a copy-paste starting point at
workflows/workflow.example.py. You can also fetch the latest template from the API at GET /workflows/default-script.The execute(ctx) entrypoint
Every workflow must define exactly one top-level execute function.
- Required and unique. There must be precisely one module-level
def execute(...). Upload validation rejects a script with zero or multiple. - Synchronous. Write
def execute(ctx):, notasync def. The worker runs your function on a thread — usectx’s synchronous methods (they handle their own I/O) rather thanawait. - Takes the context. It receives a single argument, the
WorkflowContext, conventionally namedctx. - Returns a value. Return your result — typically a
dictmatchingOUTPUT_SCHEMA. A barereturnorreturn Noneis rejected at upload. The returned object is exposed verbatim asresponse.output, and a JSON-stringified copy becomeschoices[0].message.contentfor OpenAI-shaped consumers.
execute is special. Keep helpers as plain top-level defs; the flow graph inlines them when visualizing your workflow.
The WorkflowContext import
WorkflowContext anywhere — most commonly as the type hint on execute(ctx: WorkflowContext) — you must import it, or the script fails at runtime with a NameError. Upload validation flags a missing import. The import is also what makes editor autocomplete work for the full ctx surface.
Input and output schemas
INPUT_SCHEMA and OUTPUT_SCHEMA are optional module-level dicts that describe the shape of ctx.input and your return value.
- Format. A dict mapping each field name to
{type, description, required?}. - Types.
"string","number","boolean","object","array". - Required fields. Add
"required": True. Omitting the key (orFalse) marks the field optional.
Schemas are informational, not enforced at runtime. They power the Portal — describing what
ctx.input expects and what your output contains, and rendering the Input and Output nodes in the flow diagram. Validate inputs you actually depend on inside execute.Recognized constants
| Constant | Purpose |
|---|---|
APPLICATION | The application this workflow’s LLM calls belong to. Used as the default application for ctx.chat.completions.create(...) when you pass it explicitly, and it documents intent. Binding is set at upload via --application-name / --application-id (see Uploading). |
INPUT_SCHEMA | Input shape (above). |
OUTPUT_SCHEMA | Output shape (above). |
SYSTEM_PROMPT above) are yours to use freely — they aren’t special to Maitai.
Streaming output
If callers invoke your workflow withstream=True, you can push intermediate events to them as the script runs by calling ctx.emit(...). When not streaming, emitted chunks are buffered and returned with the final response, so the same code works either way.
transform_session (optional)
Define transform_session(session) if you want to convert recorded Maitai sessions into test set items for this workflow. It takes a session and returns the input/output pair that execute would have seen:
"input" and "output" (where "output" is itself a dict). When present, the Portal lets you import sessions into a test set; when absent, that option is simply hidden.
Next
- The full runtime API: Workflow Context (
ctx) - Attach reference data: Datastores & Accessories
- Call your workflow from code: Invoking workflows