kickoff() and point CrewAI’s LLM at the AgentOS gateway. Every model call then goes through the environment’s models and guardrails, and its tokens and cost are recorded on the run. For human approval, use a Flow: the run stops at a step boundary, waits for a person in the Review queue, and the resume continues from the step after it.
Tested with CrewAI 1.15.30 and Python 3.12, using the conformance kit: 25 checks passed, including approve, edit and reject of the Flow’s hold.
The bundle
The example has two capabilities:answer, a crew of two agents, and refund, a Flow that asks a person before a refund above params.refund_limit.
vendor/, as described in SDKs. Zip the folder’s contents and deploy it (see Deploying).
Wire CrewAI’s model to the gateway
provider="openai"makes CrewAI use its OpenAI-compatible client for any model name. The name goes to the gateway exactly asconfig.modelsgives it (openai/gpt-4o-mini,anthropic/claude-sonnet-4-5,bedrock-prod/…).default_headers=inv.llm.headersadds the run token,x-agentos-run-token, to every call. The gateway ignores the API key.- Build the
LLM, agents and crews inside the handler. The run token belongs to one invocation and stops working when it answers.
Asking a person from a Flow
A crew’skickoff() can’t pause: a CrewAI agent’s tool hooks can only allow or block a call, so stopping in the middle means running the whole crew again from the start on the resume. Put the decision at a Flow step boundary instead:
1
The first invocation runs the Flow up to the decision
summarise asks the model for a summary and route sends a refund above the limit to wait_for_review, which only marks the state. The handler then saves the Flow’s state in run state and calls inv.ask(). The run is held and the container may stop.2
A person decides
The hold shows the order, the amount and the model’s summary in the Review queue, with approve, edit (for example a lower amount) and reject.
3
The resume continues after the decision
The handler loads the saved state, writes the decision into it and runs the Flow again.
summarise sees its summary is already there and skips the model, and route now goes to issue_refund or decline. Only the steps after the decision run.run_id. Code before inv.ask() runs again on the resume, so it must be safe to repeat. See Human approvals.
Run it
data, so send every key the hold asked with. See the Holds API.
Things to know
- Guardrail blocks are retried. When a guardrail blocks a model call, the gateway answers 400, and CrewAI runs the whole agent step again, up to
max_retry_limitmore times (2 by default), tools included. Setmax_retry_limit=0on agents whose tools have side effects. - Turn off telemetry. The
DockerfilesetsCREWAI_DISABLE_TELEMETRY,CREWAI_TRACING_ENABLED=falseandOTEL_SDK_DISABLED. Agents reach nothing outside the platform unless network access allows it, so telemetry calls would only fail. - Give CrewAI somewhere to write. The container runs as
nobody.HOME=/tmpandCREWAI_STORAGE_DIRgive CrewAI a writable directory. - Allow time to start. CrewAI is heavy: expect a slower start and more memory than a plain agent. Each container gets 1 CPU and 1 GB.
Next steps
Human approvals
Holds, actions, edits and the resume in detail.
Framework examples
The same patterns in other frameworks.

