Quickstart
Create your first Flow AI runtime in five to ten minutes.
Create your first Flow AI runtime in five to ten minutes.
This quickstart builds a minimal coordinator and specialist, runs the native runtime with the deterministic testing interpreter, and prints the event stream. It does not require provider credentials.
Before you begin
- Install Python 3.11 or newer.
- Use an environment with access to the private preview package.
- No Anthropic, OpenAI, or other provider API key is required for this example.
Install
Private preview access
flowai-harness is not currently available on the public PyPI registry.
To get access to the preview release, contact
aaro@flow-ai.com or
karolus@flow-ai.com before running the
install command below.
pip install flowai-harnessWhat you build
You will build one runtime with:
- A tenant identity for runtime-owned state.
- A coordinator that receives the user request.
- A specialist that can be routed to by the coordinator.
- A deterministic no-network mock response for local testing.
Create hello_flowai.py
Save the following as hello_flowai.py. It is one complete, runnable script:
import asyncio
from flowai_harness import (
TestingConfig,
create_runtime,
define_coordinator,
define_runtime,
define_specialist,
define_tenant,
)
async def main() -> None:
tenant = define_tenant("acme", "v1")
specialist = define_specialist(
name="greeter",
model="claude-haiku-4-5",
prompt="You greet the user politely.",
)
coordinator = define_coordinator(
name="hello_coordinator",
model="claude-sonnet-4-6",
routes=["greeter"],
prompt="Route greeting requests to the greeter specialist.",
)
runtime_spec = define_runtime(
tenant=tenant,
agents=[coordinator, specialist],
providers={"anthropic": {"apiKey": "unused"}},
)
runtime = create_runtime(
runtime_spec,
testing=TestingConfig(mock_response="hello from the Rust runtime"),
)
async for event in runtime.query("Say hello", thread_id="thread-1"):
print(event)
asyncio.run(main())Why `providers=` when no key is used
Every agent model resolves to a provider, and create_runtime validates
that the provider is declared in RuntimeSpec.providers — even when the
deterministic testing interpreter never calls it. The placeholder
{"apiKey": "unused"} satisfies validation without making any network
request.
Run it
python hello_flowai.pyExpected output
The runtime prints a short stream of event dictionaries. Identifiers such as
toolInvocationId differ on every run, but the shape looks like this:
{'agentName': 'hello_coordinator', 'state': 'call', 'toolInvocationId': 'inv-1955407c-815d-4f47-a49c-99f719900160', 'type': 'tool-agent'}
{'type': 'step-start'}
{'text': 'Received: Say hello\n\n', 'type': 'text'}
{'text': 'hello from the Rust runtime', 'type': 'text'}
{'data': {'hadTimeout': False, 'phases': {'llmCalls': 1, 'llmTimeMs': 0, 'subAgentTimeMs': 0, 'toolTimeMs': 0}, 'retryCount': 0, 'toolTimings': [], 'totalDurationMs': 0}, 'type': 'data-latency-summary'}
{'finishReason': 'stop', 'type': 'finish', 'usage': {'cacheCreationInputTokens': 0, 'cacheReadInputTokens': 0, 'completionTokens': 25, 'promptTokens': 50, 'totalTokens': 75}}
{'agentName': 'hello_coordinator', 'state': 'result', 'toolInvocationId': 'inv-1955407c-815d-4f47-a49c-99f719900160', 'type': 'tool-agent'}What happened
define_tenant("acme", "v1")created the tenant identity that keys all runtime-owned state.define_specialistanddefine_coordinatorbuilt two validated Pydantic agent specs; the coordinator routes greeting requests to the specialist. Coordinators withroutes=[...]receive the built-incall_agenttool by default; you do not need to listtoolkits=["agents"].define_runtimeassembled the specs into aRuntimeSpec, including the provider declaration that every agent model resolves against.create_runtime(..., testing=TestingConfig(...))selected the deterministic testing interpreter, so no API key or network access was needed.runtime.query(...)streamed events from the embedded Rust runtime, ending with the mock response text.
The testing interpreter returns a fixed response, so routing and specialist
logic are stubbed: the events show hello_coordinator, not greeter. You are
verifying wiring here, not behavior — swap in a live interpreter to see routing
and specialists actually fire.
Common errors
| Error | Fix |
|---|---|
ValueError: agent 'hello_coordinator' references provider 'anthropic' for model 'claude-sonnet-4-6', but no such provider is declared in RuntimeSpec.providers | Add providers={"anthropic": {"apiKey": "unused"}} to define_runtime(...). The testing interpreter never calls the provider, but the spec must declare it. |
ValueError: create_runtime accepts either testing or a non-default interpreter, not both | Pass either testing=TestingConfig(...) or interpreter="..." to create_runtime, never both — they are mutually exclusive modes. |
ModuleNotFoundError: No module named 'flowai_harness' | Install the package in the same virtual environment that runs the script. |
| Native extension import error | Use Python 3.11+ and reinstall the wheel for the active interpreter. |
| Agent route validation fails | Make sure every coordinator routes=[...] entry matches a registered agent name. |
Next steps
- Build the full Acme scenario-planning tutorial.
- Read the Concepts section for the mental model.
- Browse the Guides for task-focused how-tos.
