This commit removes the redundant CEL text helper, in favor of the easier interpolation syntax.
22 KiB
Flow Definition
You are writing a CrewAI Flow declaration for the user.
Use these instructions when the user asks you to create or edit a Flow.
Return one valid crewai.flow/v1 YAML or JSON document.
Treat this document as instructions for you, not as text to show the user. Follow the examples for shape and formatting, then use the API reference to check exact fields.
Output Format
Return one valid crewai.flow/v1 Flow declaration.
Do not include explanatory prose unless the user asks for it.
Build It In This Order
- Define
statefirst. Usetype: json_schemaand put the JSON Schema inline. - Put required input fields in
state.json_schema.required. Do not rely onstate.defaultto make fields required. - Add exactly one method with
start: true. - Add later methods with
listen. - Give each method exactly one
doaction object. Never makedoa list. - Pass data with
${...}mappings fromstateand completedoutputs. - Before final output, check every
listen,emit, andoutputs.some_methodreference.
Set optional fields only when you are confident they are needed. Otherwise, trust CrewAI defaults and omit them.
Method names must match ^[A-Za-z_][A-Za-z0-9_]*$.
Choose One Action Per Method
Pick the simplest action that does the job.
- Use
call: expressionfor simple reads, filters, computed values, and deterministic routing. - Use
call: agentfor one AI worker that classifies, decides, summarizes, writes, or drafts. Putrole,goal,backstory, andinputunderwith. Do not add an action-levelinputsmap to an agent. - Use
call: crewfor coordinated AI work with multiple agents or tasks. Define the crew underwith. Pass runtime values with the action-levelinputsmap.
Wire Methods Explicitly
stateis the initial shared data shape. Action results do not automatically merge intostate.- Read method results with
outputs.method_nameafter that method can run. listentargets a method name or a router-emitted event name.- Methods must not listen to their own method name.
- Method names and emitted event names share one namespace. Avoid reusing the same string for both unless the user explicitly wants that.
- Use
router: trueplusemitwhen one method chooses between named branches. - A router action must return exactly one emitted event string. It must not return JSON, a list, or an explanation.
- Use
start: truefor the single entrypoint.
If an agent is a router, make its goal say exactly what to return, for example:
Return exactly one bare value: approved, rejected, or needs_review. Do not include explanation.
Prefer call: expression when routing can be computed without an agent.
CEL And Dynamic Values
CEL is the expression language for reading Flow data and making small decisions. Use agents and crews for larger work or side effects.
Use these expression forms correctly:
- Raw CEL: use in
expr. Do not wrap raw CEL in${...}. - Use
${...}inside action mapping strings to read Flow data with CEL. Example value:Ticket: ${state.ticket_id}. - Use
statefor input data. Useoutputs.step_namefor a completed method result. - In action mapping strings, keep literal text outside
${...}and interpolate each Flow value directly. WriteTicket: ${state.ticket_id}; do not assemble the string with CEL+. - If a value is only one
${...}expression, the result keeps its type. Use this for numbers, booleans, objects, and lists. - If the string has other text, the final value is text. Non-text values become JSON.
nullbecomes empty text.
Expression examples:
Mix text and Flow data:
query: "News about ${state.topic}"
Keep a list or number type:
domains: "${state.domains}"
limit: "${state.limit}"
- Crew text: use
{name}placeholders from crew inputs. Example:Research {topic}. - Crew inputs become prompt text only when agent or task text references matching
{name}placeholders. - Passing an input that is not referenced by any
{name}placeholder does not ground the crew. If the crew needs a field, put that placeholder in an agentgoal, taskdescription, or taskexpected_output.
Available CEL variables:
state: initial input data, for examplestate.ticket.subject.outputs: completed method outputs, for exampleoutputs.classify_ticket.
Dynamic value rules:
- When an agent needs multiple fields, write one text value with labels and separators. Example value:
Ticket ID: ${state.ticket_id}; Message: ${state.message}. - Crew action-level
inputsare the actual Crew kickoff inputs. Use${...}values there for runtime data fromstateoroutputs. - Crew action-level
inputsalone are not grounding. Include placeholders for the facts the model must use. - Crew outputs are objects. Use
${outputs.research_brief.raw}for text. - For structured crew output, use fields like
${outputs.research_brief.json_dict.field}or${outputs.research_brief.pydantic.field}. - Do not pass a whole crew output to an agent input, like
${outputs.research_brief}. - Agent outputs may also be objects. Use fields like
${outputs.classify_ticket.raw}or${outputs.classify_ticket.pydantic.category}. - Use
with.inputsonly for static Crew input defaults. - Agent action
with.inputis the agent's single input value.
Do Not
- Do not invent top-level keys outside the Flow declaration shape.
- Do not use fields outside the declaration schema.
- Do not put more than one action under a method's
do. - Do not make
doa list. - Do not use CEL
+to build text in action mappings. Keep the text literal and insert each dynamic value with${...}. - Do not reference
outputs.some_methodbeforesome_methodcan run. - Do not set a method's
listento its own method name. - Do not use the same string for an emitted event and a method name unless the user asks for it.
- Do not use
emitwithoutrouter: true. - Do not rely on crew action-level
inputsalone to ground agent behavior. Inputs that do not match placeholders are effectively unused by the prompt. - Do not ask agents to infer missing facts when accuracy matters. Tell them to mark missing dates, amounts, offers, logs, or constraints as unknown.
- Do not set
config.stream: trueunless the caller is expected to consume a streaming result. For normal generated flows and CLI smoke tests, omit it.
Examples
Crew review with routed follow-up
schema: crewai.flow/v1
name: ResearchReviewFlow
state:
type: json_schema
json_schema:
type: object
properties:
topic:
type: string
audience:
type: string
required:
- topic
- audience
default:
topic: AI agent orchestration
audience: platform engineering leaders
methods:
research_brief:
start: true
do:
call: crew
with:
agents:
researcher:
role: Research analyst
goal: Research {topic} for {audience}
backstory: Expert at concise technical research.
reviewer:
role: Strategy reviewer
goal: Decide whether the research needs an executive follow-up
backstory: Experienced at reviewing technical briefs for leaders.
tasks:
- name: research_task
description: Research {topic} for {audience}.
expected_output: Key findings and tradeoffs.
agent: researcher
- name: review_task
description: Review the research and decide if an executive follow-up is needed.
expected_output: 'A brief review ending with `needs_followup: true` or `needs_followup: false`.'
agent: reviewer
inputs:
topic: Default topic
audience: Default audience
inputs:
topic: "${state.topic}"
audience: "${state.audience}"
route_followup:
listen: research_brief
router: true
emit:
- followup
- done
do:
call: agent
with:
role: Follow-up router
goal: 'Return exactly one bare value: followup or done. Do not include explanation.'
backstory: Skilled at routing reviewed research briefs.
input: "Reviewed research: ${outputs.research_brief.raw}"
write_followup:
listen: followup
do:
call: agent
with:
role: Executive communications specialist
goal: Draft a concise executive follow-up from the reviewed research
backstory: Writes crisp follow-ups for technical leaders.
input: "${outputs.research_brief.raw}"
API Reference
Use this appendix to check exact field names, required fields, linked object types, and allowed action/state shapes. Linked type names point to another section in this reference.
Flow Definition
Fields:
schema(optional): must becrewai.flow/v1; defaultcrewai.flow/v1. Declarative Flow schema identifier and version. Include it explicitly in authored declarations.name(required): string. Unique flow name used in logs, events, and traces.description(optional): string | null; defaultnull. Human-readable summary of the flow.state(required): State. State contract for the initial state and updates during execution.config(optional): Config (config); default generated default. Serializable flow-level execution configuration.methods(required): map of string to Method. Mapping of method names to method definitions.
JSON Schema State (state[type=json_schema])
Shape:
type: json_schema
Fields:
type(optional): must bejson_schema; defaultjson_schema. Inline JSON Schema used as the Flow state contract.json_schema(required): map of string to any. JSON Schema used to validate and document flow state. Declare required fields with JSON Schema'srequiredarray.default(optional): map of string to any | null; defaultnull. Default values used to initialize Flow state. Defaults are not the same as schema-required fields.
Method (methods.<name>)
Fields:
description(optional): string | null; defaultnull. Human-readable summary of what this method does.do(required): Action. Single action object executed when this method runs.start(optional): boolean | string | map of string to any | null; defaultnull. Marks the single normal entrypoint. Usetrue.listen(optional): string | map of string to any | null; defaultnull. Runs this method after one upstream method or router-emitted event.router(optional): boolean; defaultfalse. Whether the method output should be treated as the next event name. Router actions must return one event name string, with no surrounding explanation.emit(optional): list[string] | null; defaultnull. Declared router events this method may emit. Each emitted event name should be unique and should not collide with method names.
Action
Discriminated union by call.
Allowed shapes:
Crew Action (methods.<name>.do[call=crew])
Shape:
call: crew
Fields:
call(required): must becrew. Action discriminator. Use crew to run an inline Crew definition. Example:crewwith(required): inline crew definition. Inline Crew definition to load and execute for this action. Example:{"agents": {"researcher": {"backstory": "Knows the domain.", "goal": "Research {topic}", "role": "Researcher"}}, "name": "inline_research", "tasks": [{"agent": "researcher", "description": "Research {topic}", "expected_output": "Findings about {topic}", "name": "research_task"}]}inputs(optional): map of string to expression data | null; defaultnull. Runtime inputs passed to the Crew. Insert Flow values with${...}and reference each input as{name}in agent or task text. Example:{"topic": "${state.topic}"}
Crew Definition (methods.<name>.do[call=crew].with)
Fields:
agents(required): map of string to any | list[map of string to any]. Inline crew agents keyed by agent name. Example:{"researcher": {"backstory": "Expert at concise technical research.", "goal": "Research {topic}", "role": "Research analyst"}}tasks(required): list[any]. Ordered crew tasks. Example:[{"agent": "researcher", "description": "Research {topic}.", "expected_output": "Key findings about {topic}.", "name": "research_task"}]inputs(optional): map of string to any. Static default crew inputs. Values are available to crew agent and task interpolation as{name}placeholders, for example{topic}. Prefer action-level crewinputsfor runtime values fromstateoroutputs, and include placeholders for any inputs the crew must reason over. Example:{"topic": "AI agents"}
Crew Agent Definition (methods.<name>.do[call=crew].with.agents.<name>)
Fields:
role(required): string. Crew agent role. Crew inputs are interpolated with{name}placeholders such as{topic}; this is not CEL. Example:Research analystgoal(required): string. Crew agent goal. Crew inputs are interpolated with{name}placeholders such as{topic}; this is not CEL. Example:Research {topic}backstory(required): string. Crew agent backstory. Crew inputs are interpolated with{name}placeholders such as{topic}; this is not CEL. Example:Expert at concise technical research.settings(optional): map of string to any. Additional agent settings passed to the loader. Example:{"llm": "openai/gpt-4o-mini"}llm(optional): string or inline LLM config; defaultnull. Language model that runs this crew agent. Use an object when setting LLM options such asmax_tokens. Example:{"max_tokens": 4096, "model": "openai/gpt-4o-mini"}planning_config(optional): object | null; defaultnull. Agent planning configuration. Setmax_attemptsto limit planning refinement attempts before task execution. Example:{"max_attempts": 3}allow_delegation(optional): boolean | null; defaultnull. Enable agent to delegate and ask questions among each other. Example:falsemax_iter(optional): integer | null; defaultnull. Maximum iterations for an agent to execute a task Example:25max_rpm(optional): integer | null; defaultnull. Maximum number of requests per minute for the agent execution to be respected. Example:10max_execution_time(optional): integer | null; defaultnull. Maximum execution time in seconds for an agent to execute a task Example:300tools(optional): list[string | map of string to any] | null; defaultnull. Tool refs or serialized tool definitions available to this agent. String refs can use CrewAI tool names,custom:<name>, or fully qualifiedmodule:Classreferences. Example:["crewai_tools:SerperDevTool", "custom:file_read"]apps(optional): list[string] | null; defaultnull. Platform apps available to this agent. Can contain app names such asgmailor app/action refs such asgmail/send_email. Example:["gmail", "slack/send_message"]mcps(optional): list[string | map of string to any] | null; defaultnull. MCP server refs or serialized MCP server configs available to this agent. String refs can use HTTPS URLs, connected MCP integration slugs, or refs with a#tool_namesuffix for specific tools. Example:["https://api.weather.com/mcp#get_current_weather", "snowflake", "stripe#list_invoices", {"cache_tools_list": true, "headers": {"Authorization": "Bearer your_token"}, "streamable": true, "url": "https://api.example.com/mcp"}]
LLM Definition
Fields:
model(required): string. Model identifier used to instantiate the LLM. Example:openai/gpt-4o-minimax_tokens(optional): integer | null; defaultnull. Maximum number of tokens the LLM can generate. If null, CrewAI does not set an explicit output token cap and the provider's default applies. Example:4096
Crew Task Definition (methods.<name>.do[call=crew].with.tasks[])
Fields:
description(required): string. Task instructions. Crew inputs are interpolated with{name}placeholders such as{topic}; this is not CEL. Example:Research {topic}.expected_output(required): string. Expected task output. Crew inputs are interpolated with{name}placeholders such as{topic}; this is not CEL. Example:Key findings about {topic}.name(optional): string | null; defaultnull. Optional task name. Example:research_taskagent(optional): string | null; defaultnull. Name of the crew agent assigned to this task. Example:researcher
Agent Action (methods.<name>.do[call=agent])
Shape:
call: agent
Fields:
call(required): must beagent. Action discriminator. Use agent to run an individual inline Agent definition outside of a crew. Example:agentwith(required): any. Individual Agent definition to load and execute outside of a crew for this action. Put the agent input inwith.input; agent actions do not support action-levelinputs. Example:{"backstory": "Precise and concise.", "goal": "Answer user questions", "input": "${state.question}", "role": "Analyst", "settings": {"llm": "openai/gpt-4o-mini"}}
Agent Definition (methods.<name>.do[call=agent].with)
Fields:
role(required): string. Individual agent role used by a Flow agent action outside of a crew. Example:Support specialistgoal(required): string. Individual agent goal for the Flow agent action outside of a crew. Example:Draft a concise customer replybackstory(required): string. Individual agent backstory used to shape behavior outside of a crew. Example:Expert at resolving SaaS support questions.settings(optional): map of string to any. Additional agent settings passed to the loader. Example:{"llm": "openai/gpt-4o-mini"}llm(optional): string or inline LLM config; defaultnull. Language model that runs this agent. Use an object when setting LLM options such asmax_tokens. Example:{"max_tokens": 4096, "model": "openai/gpt-4o-mini"}planning_config(optional): object | null; defaultnull. Agent planning configuration. Setmax_attemptsto limit planning refinement attempts before task execution. Example:{"max_attempts": 3}allow_delegation(optional): boolean | null; defaultnull. Enable agent to delegate and ask questions among each other. Example:falsemax_iter(optional): integer | null; defaultnull. Maximum iterations for an agent to execute a task Example:25max_rpm(optional): integer | null; defaultnull. Maximum number of requests per minute for the agent execution to be respected. Example:10max_execution_time(optional): integer | null; defaultnull. Maximum execution time in seconds for an agent to execute a task Example:300tools(optional): list[string | map of string to any] | null; defaultnull. Tool refs or serialized tool definitions available to this agent. String refs can use CrewAI tool names,custom:<name>, or fully qualifiedmodule:Classreferences. Example:["crewai_tools:SerperDevTool", "custom:file_read"]apps(optional): list[string] | null; defaultnull. Platform apps available to this agent. Can contain app names such asgmailor app/action refs such asgmail/send_email. Example:["gmail", "slack/send_message"]mcps(optional): list[string | map of string to any] | null; defaultnull. MCP server refs or serialized MCP server configs available to this agent. String refs can use HTTPS URLs, connected MCP integration slugs, or refs with a#tool_namesuffix for specific tools. Example:["https://api.weather.com/mcp#get_current_weather", "snowflake", "stripe#list_invoices", {"cache_tools_list": true, "headers": {"Authorization": "Bearer your_token"}, "streamable": true, "url": "https://api.example.com/mcp"}]input(required): string. Agent prompt template. Insert Flow values with${...}, for exampleTicket: ${state.ticket_id}. Example:${state.ticket.body}
LLM Definition
Fields:
model(required): string. Model identifier used to instantiate the LLM. Example:openai/gpt-4o-minimax_tokens(optional): integer | null; defaultnull. Maximum number of tokens the LLM can generate. If null, CrewAI does not set an explicit output token cap and the provider's default applies. Example:4096
Expression Action (methods.<name>.do[call=expression])
Shape:
call: expression
Fields:
call(required): must beexpression. Action discriminator. Use expression to evaluate a CEL expression.expr(required): string. CEL expression evaluated against state, outputs, and local context.
Config (config)
Fields:
tracing(optional): boolean | null; defaultnull. Override for flow tracing; when omitted, execution defaults apply.stream(optional): boolean; defaultfalse. Whether the flow should emit streaming events when supported.memory(optional): map of string to any | null; defaultnull. Serializable memory configuration passed to flow execution.input_provider(optional): string | null; defaultnull. Provider key used to supply initial state.suppress_flow_events(optional): boolean; defaultfalse. Disable flow event emission for this definition.max_method_calls(optional): integer; default100. Maximum number of method executions allowed during one kickoff.defer_trace_finalization(optional): boolean; defaultfalse. Defer trace finalization so callers can complete tracing later.checkpoint(optional): boolean | map of string to any | null; defaultnull. Checkpointing configuration, or true to use default checkpointing.
Cross-Field Rules
- A method has exactly one
doaction object with onecalldiscriminator. listentargets method names and router-emitted event names in one shared namespace.- Methods cannot listen to their own method name.
- A router method result must match one declared
emitvalue. - Crew action-level
inputsare the Crew kickoff inputs; use CEL-wrapped strings there for runtime values. - Crew agent/task interpolation uses
{name}placeholders from evaluated crew inputs. - Agent
with.inputmust be text. Use${outputs.method_name.raw}or a text field like${outputs.method_name.json_dict.summary}.