Module 7: Cost Control Ai In Production And Mcp
8. Project: cost-controlled AI workflow
Description
By the end of this project you'll have a Terra Market AI workflow operating in production with the budget under control end to end: its spend measured in cost_log, its model verified as current, its guardrails in place, its external dependencies bounded, and —what closes the module— a monthly_budget with an alert that fires before blowing through the cap, not when the statement arrives. It's the complete answer to the question that opened all this: "the bill tripled and nobody knows why."
This matters because bringing the pieces together is where it shows whether you really understood them. Each lesson gave you an isolated piece; a production system needs them all working together and without contradicting each other. A low iteration ceiling is worth nothing if the chosen model is about to be retired. Impeccable measurement is worthless if there's no cap to compare against. A perfect alert is worthless if nobody decided what to do when it fires. The project is assembling the whole.
Connection to the module: this is the close. Lesson 2 gave you the instrument (cost_log), lesson 3 the most expensive guardrail (Max Iterations), lesson 4 the currency check, lesson 5 the decision of where the model runs, and lessons 6 and 7 the governance of the doors to the outside. Here all six converge into a single workflow operated as it should be. And a boundary that holds to the end: this project doesn't build a new agent or set up MCP from scratch. It takes workflows that already exist —built with the AI guides and set up with business-recipes M6— and puts on them the cost-operation layer this module teaches. The deliverable isn't an agent: it's an agent under control.
What you're going to build
The deliverable is the final state of a Terra Market AI workflow, ready to defend in an interview with the phrase "I operate AI in production with a controlled budget." Concretely, on ticket-classify or the AI workflow you choose, you'll leave six layers set up:
LAYER 1 — Measurement
cost_log writing one row per model call, with raw
tokens, itemized cost, and a usage_missing flag.
LAYER 2 — Agent guardrails
Max Iterations at a ceiling chosen with the real distribution.
Output validation after the agent. Time limit.
LAYER 3 — Current model
Identifier verified against the provider's page, with its
retirement date noted. Chosen by task, not by habit.
LAYER 4 — Fallback (if applicable)
An alternative path for when the model or an external service
doesn't respond, with a record of when it activates.
LAYER 5 — Budget and alert
monthly_budget set with numbers. A daily workflow that compares
the running total against the proportional line and warns before the cap.
LAYER 6 — Operation documentation
The runbook: which model, which ceiling, which budget, what was exposed,
which third parties it depends on, and what's done when each alert fires.
Let's go layer by layer. For layers 1 through 4 you already have almost everything from the previous lessons, so we go through them quickly and focus on how they fit together. Layers 5 and 6 are new and are the heart of the project.
Layer 1 — Measurement, already set up
If you followed lesson 2, cost_log is already writing. Here you only confirm three things before building on top:
-- Confirmation 1: the workflow you're going to operate is writing
SELECT COUNT(*) AS rows_last_24h
FROM cost_log
WHERE workflow_name = 'ticket-classify'
AND logged_at >= now() - interval '24 hours';
-- Must be > 0. If it's 0, the instrumentation isn't connected.
-- Confirmation 2: there are no broken rows (uncaptured tokens)
SELECT COUNT(*) AS broken
FROM cost_log
WHERE workflow_name = 'ticket-classify'
AND usage_missing = true
AND logged_at >= now() - interval '24 hours';
-- Must be 0. If not, your field paths changed: review them.
-- Confirmation 3: the raw tokens are stored, not just the cost
SELECT input_tokens, output_tokens, cost_total
FROM cost_log
WHERE workflow_name = 'ticket-classify'
ORDER BY logged_at DESC
LIMIT 5;
-- input_tokens and output_tokens must have numbers, not nulls.
If the three confirmations pass, you have a foundation. If any fails, don't go on: without reliable measurement, everything you build on top is decoration. Measurement is the one thing that can't fail in this project, because it's what everything else compares against.
Layer 2 — Guardrails, with the ceiling actually chosen
From lesson 3. Three pieces, and the first is chosen with data:
The iteration ceiling. You run the real distribution and choose the ceiling where it flattens, plus a margin:
SELECT calls_per_execution, COUNT(*) AS how_many
FROM (
SELECT execution_id, COUNT(*) AS calls_per_execution
FROM cost_log
WHERE workflow_name = 'ticket-classify'
AND logged_at >= now() - interval '30 days'
GROUP BY execution_id
) t
GROUP BY calls_per_execution
ORDER BY calls_per_execution;
With that distribution, you set Max Iterations at the high percentile of the legitimate case plus a margin — and you open the executions that hit the current ceiling before deciding, because they almost never needed that number: they ran out of passes.
Output validation. The node that verifies the agent's response has the expected shape, redirects the doubtful cases to human review, and flags agent_output_valid. It's the net that makes lowering the ceiling safe, and it goes before lowering the ceiling, not after.
The time limit. In the workflow settings, because Max Iterations bounds how many times the agent talks, not how long it can wait.
Layer 3 — Current model chosen by task
From lesson 4. Two checks:
Currency. The identifier the workflow uses is confirmed against the provider's models page, today, and its retirement date (if any) is noted in the runbook with a reminder at 60 days.
Fitness. The model matches the task. ticket-classify is classification —a closed task—, so it probably doesn't need the most capable model. If it still uses the same large model as reply-draft, this is the moment to run the comparison protocol: 200 real tickets, same sample, change only the sub-node, and compare hits and cost.
Layer 4 — Fallback, if the case justifies it
From lessons 5 and 7. Not every workflow needs it, but if yours depends on an external service or you want resilience against an AI-provider outage, the pattern is: try the cheap path, and if it fails, an error node redirects to the alternative path and leaves a record that it did. That record matters —if the fallback activates every day, it's already your real architecture and you have a capacity problem to solve.
Layer 5 — The budget and the alert
Here's what's new and what closes the module. Everything before measures and bounds; this layer is the one that warns before it's too late.
Step 1 — Set monthly_budget with numbers
The budget isn't pulled from the air. It's calculated backwards from the measured operation:
Setting monthly_budget for Terra Market's AI workflows
1. Current monthly cost, from cost_log (average AND maximum, not just one):
ticket-classify: ~22,500 calls/month
reply-draft: ~9,240 calls/month
other AI ones: whatever you measure
2. Sum the real monthly cost of all of them → base
3. Business growth margin (e.g. +20%) → × 1.20
4. Cushion for the tail of expensive executions (e.g. +15%) → × 1.15
5. monthly_budget = base × 1.20 × 1.15
The cushion in point 4 isn't optional and deserves a note: in a system with AI, the average lies and the tail matters. A budget tuned to the average blows the first month there's a run of expensive executions. The cushion is what absorbs that variance without triggering false alarms.
Store that number somewhere configurable —a data table, an environment variable—, not embedded in the alert workflow's code. When the business grows and the budget goes up, you want to touch one single place.
Step 2 — The daily alert workflow
The structure is the same you set up in module 4 to alert on failures, with a different metric inside:
Workflow: "ai-budget-guard" — Trigger: Schedule, every day at 8:00
┌────────────────┐
│ Schedule │ every morning, before the peak begins
│ Trigger │
└───────┬────────┘
│
┌───────▼────────────┐
│ Query cost_log │ sums the current month's spend
│ (SUM cost_total │ of ALL the AI workflows
│ of current month) │
└───────┬────────────┘
│
┌───────▼────────────┐
│ Code — │ compares against the proportional line
│ "Evaluate budget" │ and decides the alert level
└───────┬────────────┘
│
┌────┴─────┐
│ If │
└──┬────┬──┘
ok │ │ alert
│ │
(nothing) ▼
┌─────────────┐
│ Notify │ email / Slack to the owner
└─────────────┘
The heart is the Code node that evaluates. And here it's best that it be pure arithmetic over data that already arrived —the accumulated spend was brought by the previous node with a SQL query— because that's exactly what the Code node can do in n8n 2.0 without going out to the network:
// Node: Code — "Evaluate budget"
// Mode: Run Once for All Items
// Input: the month's accumulated spend, brought by the previous SQL node.
// Output: the alert level and the message.
// No network or files — just comparing numbers that are already here.
// The budget lives outside the code, in a config table. Here it
// arrives already resolved by a previous node, or you read it from the input.
const data = $input.first().json;
const monthlyBudget = data.monthly_budget; // e.g. 500 (your currency unit)
const spentSoFar = data.spend_this_month; // what the SQL summed
// The proportional line: how much you SHOULD have spent at this point
// in the month if the spend were even. On the 10th of a 30-day month, you
// should be at a third. Comparing yourself against this warns you on the 10th, not the 30th.
const now = new Date();
const dayOfMonth = now.getUTCDate();
const daysInMonth = new Date(
now.getUTCFullYear(),
now.getUTCMonth() + 1,
0
).getUTCDate();
const proportionalLine = monthlyBudget * (dayOfMonth / daysInMonth);
// Two thresholds, not one. The warning one is that you're above pace;
// the emergency one is that you've almost eaten the whole budget.
const projectedMonthEnd = spentSoFar * (daysInMonth / dayOfMonth);
let level = 'ok';
let message = '';
if (spentSoFar >= monthlyBudget * 0.95) {
// Emergency: you almost blew the cap, and there are days of month left.
level = 'emergency';
message =
`EMERGENCY: AI spend at ${spentSoFar.toFixed(2)} of ` +
`${monthlyBudget} (${((spentSoFar / monthlyBudget) * 100).toFixed(0)}%), ` +
`and there are still ${daysInMonth - dayOfMonth} days of the month left.`;
} else if (spentSoFar > proportionalLine) {
// Warning: you're going faster than the pace that fits in the budget.
level = 'warning';
message =
`WARNING: AI spend (${spentSoFar.toFixed(2)}) above pace. ` +
`Projection to end of month: ${projectedMonthEnd.toFixed(2)} ` +
`against a budget of ${monthlyBudget}.`;
}
return [{
json: {
level, // 'ok' | 'warning' | 'emergency'
message,
spent_so_far: spentSoFar,
monthly_budget: monthlyBudget,
proportional_line: proportionalLine,
projected_month_end: projectedMonthEnd,
should_alert: level !== 'ok',
},
}];
It's worth pausing on two decisions in that code.
First: the proportional line, not the total. Comparing the accumulated spend against the whole budget is worth nothing until the end of the month — the bill already does that. The proportional line compares you against the pace: on the 10th of a 30-day month, you should be at a third of the budget. If you're at half, you're going to overshoot, and you know it on the 10th with twenty days to react. That anticipation is the whole difference between operating and regretting.
Second: two thresholds, not one. The warning one —"you're above pace"— is informative and gives you time to investigate without urgency. The emergency one —"you've almost eaten the budget"— is the one that demands action today. A single threshold forces you to choose between alerting too early (and people ignoring the alert) or too late (and it being useless). Two thresholds give each situation its level of urgency.
Step 3 — The decision almost nobody writes: what's done when it fires
An alert nobody knows how to respond to is an alert that gets ignored. The most important part of this layer isn't the code: it's deciding in advance what happens when each level fires, and writing it down.
AI budget response protocol — Terra Market
WARNING (spend above pace)
→ The person on duty runs the diagnostic queries:
did the volume go up? did the cost per execution go up? did a
new workflow appear? did someone touch a Max Iterations?
→ If it's legitimate business growth: monthly_budget is adjusted
and documented.
→ If it's a leak (lesson 2): the leak is fixed.
→ Deadline: same business day.
EMERGENCY (95% of the budget with days of month ahead)
→ Immediate action. The options, from least to most drastic:
1. Identify the workflow driving the spend (query by
workflow_name) and evaluate whether it can be paused without harming the business.
2. Temporarily lower Max Iterations or the model of the expensive workflow.
3. If a service exposed over MCP is in a loop, cut off its access.
→ And a business decision that is NOT technical: is overspending
authorized this month, or is the service degraded? That decision
is made by whoever has budget responsibility, not the person
on duty. The protocol says who it's escalated to.
Notice the last line, because it's what makes the protocol professional. The technical person detects and contains; the decision to overspend or degrade the service is a business one, and the protocol says who it's escalated to. A protocol that asks whoever's on duty to decide whether Terra Market can afford to overshoot the budget is badly designed: that's not their decision.
Layer 6 — The runbook
The final deliverable isn't the workflow: it's the document that lets another person operate it when you're not there. Half a page, and it's what separates a delivered project from an abandoned one.
AI operation runbook — Terra Market
AI WORKFLOWS IN PRODUCTION
ticket-classify model: <id> · Max Iterations: 7 · retirement: <date>
reply-draft model: <id> · Max Iterations: 5 · retirement: <date>
[each with its model, its ceiling, and its known retirement date]
BUDGET
monthly_budget: <number> (base × 1.20 × 1.15, reviewed <date>)
Lives in: <where the config is>
Alert: ai-budget-guard, daily at 8:00
WHAT'S DONE WHEN EACH ALERT FIRES
[the response protocol above]
MCP EXPOSURE (if applicable)
Exposed: <list of exposed workflows, or "nothing">
To whom: <consumers>
How to revoke: <procedure>
EXTERNAL DEPENDENCIES (if applicable)
<external MCP server>: used by <workflow>, quota <limit>,
failure plan: <fail / degrade / alternative>
PERIODIC REVIEW (quarterly, owner: <who>)
- Model currency against the provider's page
- Iteration distribution (did someone touch a ceiling?)
- Spend against budget and against worst case
- usage_missing rows in cost_log (did measurement break?)
- Status of MCP exposures and of the instance server
That document is the real deliverable. The workflow works without it; the operation doesn't survive without it. It's also what answers, in writing and in advance, the question that opened the module: if the bill triples, here's exactly what's reviewed, in what order, and who decides.
Common mistakes
Building the layers without verifying that the one below works (practical). What happens: the budget alert is set up over a cost_log that has broken rows, and the alert never fires because the measured spend is artificially low — it's summing zeros. Why it happens: the layers are built top-down out of enthusiasm, when the dependency is bottom-up. How to detect it: before each layer, run the previous layer's confirmation. The alert depends on the measurement; the measurement depends on nothing. How to fix it: build in order —measurement, guardrails, model, fallback, budget, runbook— and don't advance until the one below passes its confirmations. It's the same principle as any system: you don't put up the roof before the foundations.
Setting the budget against the average and forgetting the tail (conceptual). What happens: monthly_budget is calculated with the average cost per execution, tuned to the cent, and the first month with a run of expensive executions the emergency alert fires on the 12th with nothing being wrong — there was just normal variance. Why it happens: the average is the number that comes out of a query first, and it looks like the right one. How to detect it: compare the maximum against the average in your cost_log. If the maximum is several times the average, a budget with no cushion will give false alarms. How to fix it: the 15% cushion isn't fat, it's what absorbs the variance inherent to a system with AI. A budget that fires on normal variance teaches people to ignore the alert, which is worse than not having it.
Alert without a response protocol (conceptual). What happens: the budget alert fires, the email arrives, and nobody knows what to do — because it was never decided. The email is filed "to look at later" and the month goes over budget anyway. Why it happens: building the alert is the technical, satisfying part; deciding the response is the boring, political part, and it's left for later. How to detect it: ask the person who would receive the alert what they'd do on receiving it. If they don't know, there's no protocol. How to fix it: the response protocol is written before turning on the alert, with the key decision —who authorizes overspending— assigned to whoever has budget responsibility. An alert without a protocol isn't a control, it's noise.
Handing over the workflow without the runbook (practical). What happens: the workflow is impeccable, with all its layers, and six months later nobody knows why Max Iterations is at 7, or what the budget is, or what's done when the alert fires. The person who set it up changed teams and took all the context in their head. Why it happens: the workflow is the visible deliverable and the runbook is invisible work that "can be done later." How to detect it: if the operation knowledge lives only in one person, it's not delivered, it's on loan. How to fix it: the runbook is part of the project, not an optional appendix. Half a page that turns a workflow only its author understands into a system the team operates. It's the difference between "I operate AI in production" and "I set up something that runs as long as I'm around."
Exercises
Exercise 1 — Assemble the build plan. You're going to operate ticket-classify with the six layers. You have cost_log already writing from lesson 2, but nothing else is set up. Write the order in which you build the six layers, and for each one, what you verify before moving to the next. Justify why that order and not another.
See solution
The order is bottom-up, because each layer depends on the previous one:
| # | Layer | What I verify before advancing | Why it goes here |
|---|---|---|---|
| 1 | Measurement | The three confirmations: it writes rows, zero usage_missing, raw tokens present | It's the foundation. Everything else compares against these numbers. If they lie, everything above lies |
| 2 | Guardrails | The iteration distribution is run, the ceiling chosen with data, the output validation set up before lowering the ceiling, and the time limit in place | It needs the measurement (the distribution comes from cost_log) and it protects everything that comes: without a ceiling, the spend is uncontrollable and the budget is theater |
| 3 | Current model | Identifier confirmed against the provider's page, retirement date noted, and fitness to the task evaluated | It can go in parallel with layer 2, but it's best before the budget: if you're going to change models, the cost per execution changes and the budget is calculated with the final model |
| 4 | Fallback | That the alternative path works and that it records when it activates | It depends on the model and the dependencies being decided (layers 3 and, if applicable, the MCP ones). There's no point setting up a fallback before knowing what it's a fallback for |
| 5 | Budget and alert | monthly_budget calculated with the real measured cost (already with the final model and ceiling), alert workflow tested with real data, and the response protocol written | It goes near the end because it's calculated with the final numbers: if you set it before choosing the ceiling and the model, you set it over numbers that are going to change |
| 6 | Runbook | That another person can read it and operate the system without asking you anything | It goes last because it documents everything above. You can't document what doesn't yet exist |
The logic of the order is a single one: each layer consumes the one below. The measurement depends on nothing; the guardrails need the distribution the measurement gives; the budget is calculated over the cost that the already-chosen model and ceiling produce; and the runbook documents the finished whole.
The classic mistake is to start with the budget alert because it's the flashiest. But an alert calculated over a broken measurement, or over a cost per execution that's going to change when you adjust the ceiling, is an alert you have to redo. Building in the order of the dependencies avoids redoing.
Why it works: the exercise makes explicit that a layered system is built from the foundation, and that the order isn't preference but dependency. Recognizing what needs what is what distinguishes a setup done once from one redone three times.
Exercise 2 — Design the two-threshold alert. Terra Market set monthly_budget at 600 (its currency unit) for all its AI workflows together. You're on day 12 of a 30-day month and the accumulated spend is at 310.
(a) Calculate the proportional line for day 12. (b) Calculate the projection to end of month. (c) What alert level corresponds with the thresholds from the lesson's code (warning if it exceeds the proportional line, emergency if it exceeds 95% of the budget)? (d) The person on duty receives the warning. Write the first three diagnostics they run, in order, and what they'd do with each result.
See solution
(a) The proportional line for day 12:
proportional_line = 600 × (12 / 30) = 600 × 0.4 = 240
On day 12 you should be at 240 spent if the spend were even.
(b) The projection to end of month:
projected_month_end = 310 × (30 / 12) = 310 × 2.5 = 775
At the current pace, you'd end the month at 775 against a budget of 600. You'd overshoot by 175, a 29% overrun.
(c) Level: warning. The spend (310) exceeds the proportional line (240), so the warning condition is met. But it doesn't exceed 95% of the budget (which would be 570), so it's not an emergency. And this is exactly what you want: the alert fires on day 12, with the projection saying you're going to end 29% over, and with 18 days to react. Without the proportional line, this same case wouldn't have fired anything until the accumulated spend approached 600 — probably around day 23, with a week to react instead of eighteen days.
(d) The first three diagnostics, in order:
-- Diagnostic 1: which workflow drove the spend?
SELECT workflow_name, SUM(cost_total) AS spend, COUNT(DISTINCT execution_id) AS execs
FROM cost_log
WHERE logged_at >= date_trunc('month', now())
GROUP BY workflow_name
ORDER BY spend DESC;
What I'd do with the result: if a workflow dominates the spend unexpectedly, that's the suspect and I go to it. If the spend is spread out as always, the problem is general volume, not a single culprit.
-- Diagnostic 2: did the cost per execution go up, or did the volume?
SELECT date_trunc('day', logged_at) AS day,
COUNT(DISTINCT execution_id) AS executions,
AVG(cost_total) AS avg_cost_per_call,
SUM(cost_total) AS daily_spend
FROM cost_log
WHERE workflow_name = 'ticket-classify'
AND logged_at >= now() - interval '15 days'
GROUP BY day ORDER BY day;
What I'd do: if the number of executions went up, it's business growth —legitimate, adjust the budget. If the cost per call went up with the same volume, someone touched something —a ceiling, a prompt, a model— and it's a leak to fix.
-- Diagnostic 3: did the number of iterations per execution change?
-- (the "someone raised Max Iterations" detector)
SELECT date_trunc('day', logged_at) AS day,
COUNT(*)::float / COUNT(DISTINCT execution_id) AS calls_per_execution
FROM cost_log
WHERE workflow_name = 'ticket-classify'
AND logged_at >= now() - interval '15 days'
GROUP BY day ORDER BY day;
What I'd do: if the calls per execution went up from one day to the next without the volume changing, someone moved Max Iterations or the prompt grew. That's the exact case that opened the module, and now I detect it the same day instead of the following month.
The sequence of the three diagnostics isn't accidental: first who (which workflow), then what kind of increase (volume or cost per execution), and then the most common cause of the second (iterations). In three queries you go from "the spend is running high" to "it was this, caused by that change, on that day."
Why it works: the exercise shows that the proportional line turns a late alert into an early one, and that a warning is only useful if it comes with a diagnostic procedure that resolves it. Running the three queries is the difference between "I received an alert" and "I found the cause."
Exercise 3 — Write the emergency protocol. Terra Market's AI budget reached 95% on day 20 of a 30-day month. The emergency alert fired. Write the complete response protocol: what's done, in what order, who decides what, and what's documented afterward. Bear in mind that this protocol will be run by someone who maybe didn't set up the system.
See solution
A reference protocol:
AI budget emergency protocol — Terra Market
Activates when: the accumulated AI spend reaches 95% of
monthly_budgetwith days of the month ahead. It's fired byai-budget-guardautomatically.Phase 1 — Contain (person on duty, immediate):
- Run the by-workflow diagnostic (grouped spend query). Identify which one is driving the spend.
- Run the iterations-per-execution diagnostic. If a workflow raised its calls per execution without the volume changing, it's almost certainly a
Max Iterationssomeone touched or a prompt that grew — it's the fastest and most reversible containment.- Review the MCP exposures: if an exposed service is being called in a loop by an external agent, cutting off its access is an immediate containment that doesn't harm the business itself.
Phase 2 — Stabilize (person on duty, same day):
- On the workflow driving the spend, apply the least drastic containment that works, in this order: lower
Max Iterationsto a conservative value, or temporarily switch to a more economical model, or —if it's a low-criticality workflow— pause it. Each action is recorded.- Confirm with a query that the spend per hour dropped after the action. If it didn't drop, the cause was another: go back to phase 1.
Phase 3 — Decide (budget owner, NOT the person on duty):
- The business question: is overspending authorized this month, or is the service kept degraded until the end of the month? This decision is not made by whoever's on duty. The protocol escalates to:
<name / role of the budget owner>.- Depending on the decision: either
monthly_budgetis raised temporarily and the containments are reverted, or the degradation is kept and the affected team is informed (support, in the case ofticket-classify).Phase 4 — Document (person on duty, within 48 hours):
- Write down what happened: which workflow, what cause, what containment was applied, what the owner decided, and what changed permanently.
- If the cause was a leak (a touched ceiling, a grown prompt, a published test workflow), fix it at the root so it doesn't happen again. An emergency that's contained but not fixed comes back the following month.
- If the cause was legitimate business growth, adjust
monthly_budgetpermanently and document the new number.
Three decisions in that protocol are worth it.
First: the separation between containing and deciding. Phases 1 and 2 are technical and run by whoever's on duty, now. Phase 3 is business and run by whoever has budget authority. Mixing them —asking whoever's on duty to decide whether the company can afford the overrun— is the most common design mistake, and it produces paralysis: the technical person doesn't dare to decide something that isn't theirs to decide, and meanwhile the spend continues.
Second: containment goes before the decision. You don't wait for the owner to decide before acting. You contain first —reversibly— and decide afterward calmly. Lowering Max Iterations temporarily doesn't harm anything and can be reverted in a minute if the decision is to authorize the spend. Waiting for the decision with the clock running, no.
Third: phase 4 distinguishes a leak from growth. An emergency from a leak is fixed at the root. An emergency from growth becomes a new budget. Confusing the two —raising the budget to paper over a leak, or containing legitimate growth that's going to come back— leaves the problem for the following month.
Why it works: the protocol is designed to be run by someone who didn't set up the system, which is the real case of an emergency —it happens when it happens, not when the expert is available. The clear separation of who does what, and the contain-before-deciding order, are what turn an emergency into a managed incident instead of chaos. And it's exactly the kind of document that answers, once and for all, the question that opened the module.
Summary: what you built and what you can defend
You finished the module, and you finished with a production system, not a theory.
You built a Terra Market AI workflow operated with the budget under control end to end, in six layers that rest on one another: the measurement (cost_log, with raw tokens and a breakage flag), the guardrails (iteration ceiling chosen with the real distribution, output validation, time limit), the current model (verified against the provider's page and chosen by task), the fallback when the case justifies it, the budget with an alert (monthly_budget calculated with real numbers, compared against the proportional line, with two thresholds and a response protocol), and the runbook that lets another person operate it.
And above all you closed the circle that lesson 1 opened. The question was: "the AI bill tripled with 8% more volume, and nobody knows why." Now you have the complete answer, and it isn't one: it's a system that makes that question impossible to leave unanswered again. Because you measure each call, so you know how much each thing cost. Because you bound the loop, so a touched Max Iterations doesn't escape you. Because you verify the model, so a retirement doesn't surprise you. Because you govern the doors to the outside, so an external agent or a third-party service doesn't drain your account silently. And because you alert before the cap, so you find out on the 12th with eighteen days to act, instead of on the 30th with the bill in hand.
What you can say in an interview, and back it up with the runbook in hand: "I operate AI in production with cost under control. I know exactly what each workflow costs me, I have caps that warn me before I blow through them, I verify that my models are still alive, and I have written down what's done when something spikes and who decides it." That sentence is the difference between someone who put together an agent that works and someone who operates an AI system as a professional. And it's exactly what this module taught you to build.
Congratulations on getting this far. You closed the most uncomfortable module to operate in the whole guide —the only one where the problem is invisible until the bill arrives— and you came out with the tools to make it stop being so.
Resources
- AI Agent node — n8n Docs — the project's central node, with
Max Iterationsand the rest of the guardrails you set up in layer 2. - Code node — n8n Docs — the tool with which you evaluate the budget: pure arithmetic over data that already arrived, within the limits of n8n 2.0.
- Schedule Trigger — n8n Docs — the daily trigger of the budget alert workflow.
- Data tables — n8n Docs — where
cost_logandmonthly_budgetlive if you don't use PostgreSQL. - Anthropic pricing · OpenAI API pricing · Google Gemini pricing — the current prices for
cost_log's constants and for the budget calculation. Review them every quarter. - Module 2 of this guide — cost measurement and the five leaks, the project's foundation.
- Module 4 of this guide — the observability and alerts layer where the budget workflow plugs in naturally.
- Sibling guide
n8n-business-automation-recipes-guide, module 6 — the setup of MCP and local models, for the workflows this project operates but doesn't build.