Architecture: when a flow, when a Met
The ladder from a template to an autonomous Met, what each rung costs, how flows and Mets combine in both directions, and an end-to-end example.
Build an AI agent sets out the core decision: an agent decides the sequence on every run; a flow has it decided by whoever builds it. This guide goes one step further, because in practice almost nothing good is only one of the two. What works in production is a flow that calls a Met only at the step that needs judgment, or a Met that calls a flow for what cannot be improvised.
The reason is twofold. Every AI step spends Energy and can get it wrong; every fixed step spends nothing and always does the same thing. The fewer steps depend on the model, the cheaper and more predictable the process.
The ladder
Ordered from the cheapest, most controllable rung to the most expensive and open-ended:
| what it is | spends Energy | use it when | |
|---|---|---|---|
| 1. Template, rule or code | fixed text, flow.condition, data.code, buttons with channel.ask_options | no | the answer is known in advance or can be computed |
| 2. One bounded call | an AI Field or an isolated Run (tool_policy: "none") | one call | you need to read or write language, but the task is a single one and needs no tools |
| 3. Ask a Met | the agent.ask node inside a flow | that step | one step needs a Met's judgment or writing; the rest of the process stays fixed |
| 4. A Met that converses | the agent.handoff node: from there on the Met handles the contact | every turn | the conversation cannot be predicted; the Met calls Functions for what cannot be improvised |
Start at the bottom and climb only when the rung below falls short. The signals to climb:
- From 1 to 2: the input is free text and the rule has turned into a list of words that never ends.
- From 2 to 3: the task needs the tone, the data or the tools of a specific Met.
- From 3 to 4: you cannot tell how many turns the conversation will take or in what order.
And the signals to step down, which are the ones that save the most: a Met that always does the same steps in the same order is a flow or a Function; a Met that picks between three fixed options is a button menu; a Met that only writes one sentence does not need its ninety tools.
Rung 1: template, rule and code
Everything that does not go through a model:
flow.conditionbranches the flow by groups of conditions (all or any). It compares witheq,ne,gt,gte,lt,lte,contains,starts_with,in,not_in,has_any,has_none,is_setandis_empty, and withmatches_term, which looks for whole words ignoring case, accents and punctuation. If no group matches, it exits through "Si no" (else).data.codetransforms data with JavaScript: it receivesentradaand whatever you return lands in@{node:<id>.result}. It runs isolated, with no internet, files or modules, with 1 second, 64 MB of memory and a result of up to 256 KB. The@{...}references go in its input data, not inside the code.channel.ask_optionsasks the contact a question and waits for their choice with buttons or quick replies, without spending the Met's Energy. It is the way to classify when the options are few and known: letting the person choose costs less and gets it wrong less often than guessing what they meant.- Templates and fixed messages: the messaging nodes send text you wrote, with references to the trigger's data.
Rung 2: one bounded call
When you need language but not an agent:
- An AI Field fills a collection cell with the field's prompt: classify a lead, summarize a note, pull the city out of an address.
- An isolated Run runs a Met with
tool_policy: "none": it works only with theinput, its attachments (PDFs and images) and the Met's instructions. It loads no skills, integrations, history, variables or workspace context, and if the model tries to use a tool the run stops without dispatching it. Detail in Run Mets.
const run = await met.runs.create({
met: 'Extractor',
tool_policy: 'none',
input: 'Return only the tax ID and the total from this text, as JSON: ...',
});
Rung 3: Ask a Met (agent.ask)
The agent.ask node ("Pedirle a Met") hands a task to a Met in the workspace with two fields: the Met (met_id) and the instruction (prompt), which can carry references to earlier nodes. The answer lands in @{node:<id>.text}.
Two things worth knowing before you use it:
- The Met runs in full, with its instructions, skills and tools. The node has no level of its own: it uses the Met's. So the Met you pick for a bounded step sets the cost of that step. For a short sentence, use a specialized Met on the agile level, with brief instructions and its tools switched off (below, bounded context).
- The answer is free text, with no schema. If it is going out to someone, validate it first (below, control the output).
Rung 4: a Met that converses
The agent.handoff node binds a Met to the conversation: from there on that Met answers the contact. It is the right rung for handling people, and the worst one for running procedures: anything with fixed steps —charging, booking, logging an order— goes in a Function that the Met calls, with parameters the Function validates.
Both directions of the combination
| direction | how | when |
|---|---|---|
| flow → Met | agent.ask for one step; agent.handoff to hand over the conversation | the process is fixed and one of its steps needs judgment or writing |
| Met → flow | an AI Function with an HTTP handler or with flow_id; the flow returns its result with the function.result node | the Met converses and, at some point, has to run something it cannot improvise |
In the second direction, the Function's parameters are the contract: with enum_values the Met can only send one of the values you allowed, and what happens next is decided by your flow or your backend, not by the model.
What each thing costs
Logic, data and messaging nodes spend no Energy. Conditions, code, buttons, templates, waits, loops and CRM reads or writes run without a model. The nodes that spend are the ones that invoke AI: agent.ask, agent.handoff, agent.nudge, image.generate, image.edit, voice.generate, video.generate, and a flow.action node when one of its actions puts a Met to work. An mcp.call node does not go through a model, but the tool it calls may have its own cost, for example one that generates images.
What makes a Met expensive is not just its level. Every call to the model carries its instructions and the definition of all its active tools, even when the turn is trivial: a Met with a long prompt and dozens of tools pays for that context to write one sentence. The part of the context that repeats is charged less when it comes from cache, but it is not free. And the level multiplies all of the above.
Routing costs too. A Run without met is handled by the workspace's main Met, which can delegate to another Met: two executions where one would do. With met, the Run goes straight to that Met, without going through the orchestrator.
How to measure it: GET /billing/executions filters by met_id and by run_id, and totals adds up the whole filter (What each call costs). There is no per-flow cost in the API today, so use a trick: give your flow's AI step its own Met. Filtering by that met_id tells you exactly what that step costs, run by run.
Levels
Each Met has a level, chosen with model when you create or edit it (Mets and their tools):
model | for what |
|---|---|
agil | fast and the one that spends the least Energy per answer: classifying, extracting, writing a short sentence, answering what is already in its instructions |
brillante | the everyday one: handling people, combining data, writing with judgment |
genio | reasons more and spends more: decisions with many variables, long and delicate texts |
await met.agents.update(writerId, { model: 'agil' });
The practical rule: agile for bounded tasks. If the task fits in a two-line instruction and a one-sentence answer, raising its level does not make it better; it only makes it more expensive. The image and video nodes in a flow pick their own level; agent.ask uses the Met's.
Bounded context
The less context a Met loads, the less each turn costs and the fewer ways it has to drift:
- Switch off what it does not use with
disabled_tools. The valid names come frommet.agents.tools(id)(Mets and their tools). - Hide the collections that are none of its business with
expose_to_agent: false. - Prefer several specialized Mets to one that knows everything. A writer Met with five lines of instructions and its tools switched off is the right Met for an
agent.askthat writes one sentence. - To extract or classify a single thing, use an isolated Run (
tool_policy: "none"): it does not even load the history.
Control the output
A model can return something reasonable but wrong. Before its output reaches a customer, a flow checks it without AI:
- Validate with code.
flow.conditioncompares values but does not measure lengths or look for patterns, so the validation goes in adata.codethat returns a yes or a no, and the condition reads it:
js // Input data: {"texto": "@{node:redactar.text}"} const t = String(entrada.texto || '').trim(); const ok = t.length > 0 && t.length <= 120 && !/https?:\/\/|www\./i.test(t); return { ok, texto: t };
Then, a flow.condition with @{node:validar.result.ok} equal to true.
- Keep a fixed fallback. The "Si no" (else) branch sends text you wrote. If the model fails, the contact gets something correct instead of nothing or something odd.
- Whatever publishes, charges or sends goes through a person. When a Met asks to post on social media, charge, invoice, spend ad budget or send a template that Meta bills, the action can wait for someone in the business to approve it (Human approvals). A flow has no approval node: what it sends on its own goes out unreviewed, which is why it has to be fixed text or validated output.
- Narrow what the Met can ask for. In a Function,
enum_valuesand required parameters make what reaches your backend have the shape you expect.
End-to-end example: replying to comments
This is the pattern Meteor uses to reply to comments on its own posts: when someone comments the keyword, they get the information by private message, a short public reply and a "Like". Only one of the six steps uses AI.
| step | node | what it does | spends Energy |
|---|---|---|---|
| 1 | trigger.start with the social.comment_received trigger | starts on a new comment on the chosen account that contains the keyword (contains, case-insensitive) | no |
| 2 | mcp.call → meta_reply_to_comment_private | sends a fixed private text with the information and the link | no |
| 3 | mcp.call → meta_like_comment | likes the comment (Facebook only; skipped on Instagram) | no |
| 4 | agent.ask | asks the writer Met for one sentence to reply in public | yes |
| 5 | data.code + flow.condition | validates the sentence: that it exists, that it is at most 120 characters and that it has no links | no |
| 6 | mcp.call → meta_reply_to_comment | posts the validated sentence or, through the "Si no" (else) branch, a fixed fallback text | no |
The comment's data arrives in the trigger: @{trigger.payload.comment_id}, @{trigger.payload.comment_text}, @{trigger.payload.platform} and @{trigger.payload.account_id}. Each comment is claimed before the flow runs, so the same comment never triggers it twice.
The instruction for step 4 fits in three lines:
Write a public reply of a single warm sentence, at most 120 characters,
with no links or contact details, for this comment: @{trigger.payload.comment_text}
The writer Met runs on agil, with brief instructions about the brand's tone and its tools switched off with disabled_tools. What is at stake with AI is small —one sentence— and even so it does not go out without passing validation.
Routines are this same pattern
Met's Routines —create and post on social media, advertise what you sell, follow up with your customers— are built this way inside:
- Choosing is a button. At each step the person picks a path, and picking it calls no model.
- The assignment is a template. What the path's Met is asked to do is put together from fixed text and the business's data.
- One delegation per step. Each AI step is a single assignment to a single Met. Steps that need no AI —working out whom to follow up with from the orders, for example— are done by the server.
- The output is validated. The Met closes with a block of structured data that is read, bounded and normalized; if it does not arrive or cannot be parsed, the step keeps its text and no figures: they are never made up.
- Whatever publishes goes through approval. During a routine, actions that publish or spend ad budget always wait for a person.
- Cost is measured per run. Each step is a turn with its Energy, and when the routine closes you see what the whole run spent.
FAQ
Does a flow with no AI steps spend Energy?
No. Logic, data and messaging nodes do not invoke a model. Watch out for what does cost outside of Energy: a WhatsApp template outside the 24-hour window is billed by Meta.
Can I choose the level of an agent.ask node?
Not per node: the step uses the level of the Met you pick. If you need one step on agile and another on brilliant, use two Mets.
When is an isolated Run better than agent.ask?
When you call from your backend and the task is a single extraction or classification over a text or a document. The isolated Run loads no tools or context; agent.ask runs inside a flow and the Met does it with everything it has.