The allocator
The allocator turns phases and envelopes into today's budgets. It reads what every campaign wants, funds them in order under the caps you set, and writes the moves as drafts. It moves no money itself: what it produces is change requests at the gate, like every other write in Tempio.
It is off in every workspace until somebody turns it on, in Settings → Approvals, beside the rules it is held to. The switch asks first: Turn on automatic budget moves? says Tempio will draft budget moves between campaigns each day and that the rules you wrote clear the ones they cover without you, and the switch stays where it was until you press Turn on. Turning it off is one press. The section reads:
Automatic budget moves
Once a day, at the hour you pick in this workspace's reporting time zone, the allocator reads every active campaign's envelope and the phase it is in, funds them in phase order under your daily cap, and drafts the moves as one budget batch. It drafts and never applies: the batch waits at the gate, approved by you, or by a rule you wrote.
The same section carries the hour it runs at and a link that says Write a policy that approves its batches — "A rule over update_budget, within the amounts you allow, is what makes its batches hands-off."
Before it runs: a cap somebody chose
The allocator funds everything under the workspace's daily cap, and that one number decides every throttle it makes. If the workspace has written no guardrail of its own, so the cap resolves to Tempio's default for the currency, the run refuses and writes nothing: it names the default it would have used and asks you to set a workspace guardrail in Settings → Guardrails first.
The refusal does not burn the day. Set the cap and the next run works the same hour. A dry run answers regardless — it tells you where the cap came from, which is usually how a workspace finds out it never set one.
What it reads
- Every active campaign carrying an enabled envelope. A campaign without one has not been handed to the allocator at all.
- The phase covering today, and its multiplier.
- Each campaign's goals and their verdicts over their own windows.
- The workspace's resolved daily cap, and each account's.
- The guardrail's maximum budget movement per day.
- Whether a campaign has at least seven days with spend, which is the floor below which its goals say nothing.
How it decides, in one pass
- What each campaign wants. The envelope times the multiplier of today's phase. A campaign with no phases at all wants its whole envelope; one whose phases have all ended wants nothing.
- What its goals do to that. A campaign missing a goal whose action is
proposeis held at today's budget — never raised, because a campaign missing its number is not the one to scale, and never lowered here, because throttling is the funding pass's job. A campaign beating anat_mostproposegoal by more than a fifth becomes raise-eligible. Below the seven-day floor nothing is said either way: a cost per acquisition computed over two days is not a measurement. - The order.
closingfirst, thenlaunch, thencustom, thenhold, then a campaign with an envelope and nothing said about when it is hot. Within a kind: raise-eligible first, then priority (lower first), then goal margin (best first), then the campaign's id — that last key is what makes the pass deterministic, so the same inputs give the same answer every run. - Funding. Down the order until the workspace cap runs out, holding each account under its own cap as well. Whatever is below the line is throttled to what is left. A campaign denominated in a currency the workspace cap is not in is held to its account's cap alone and named in the report; money never crosses currencies here.
- The clamp and the floors. Every move is held to the guardrail's maximum movement in a day, rounded to the currency's minor unit. A move smaller than one percent of what the campaign is running, or smaller than 100 minor units, is dropped — below that it costs a reviewer more attention than it can be worth, and a batch full of them teaches a workspace to approve without reading. A budget of zero is never drafted: that is a pause, and a pause is a person's act.
- The drafts. One
update_budgetbatch per connection, one row per campaign that moved, at most fifty moves in a run: past that a campaign readsbatch_limitand is left for tomorrow. Each batch is reviewed and applied as a unit, and it passes every guardrail and approval chain any other draft passes.
Only campaigns whose budget lives at campaign level are moved. On a campaign
budgeted at ad-group level the campaign figure is a sum of its children rather
than a field, and writing to it would replace every ad set's own budget — so such
a campaign is loaded, named in the report under budget_not_at_campaign, and
left alone.
Why a campaign ended where it did
Every campaign the allocator looked at appears in the report, moved or not, with one of these reasons.
| Reason | What happened |
|---|---|
funded | It got what it wanted, and the budget moved |
throttled | The cap ran out above it, so it got less |
phases_ended | Every phase has ended, so it wants nothing |
goal_missed | A propose goal is being missed; held at today's budget |
unchanged | It wants what it is already running |
below_floor | The move was smaller than one percent, or than 100 minor units |
clamped | The movement guardrail left it where it was |
no_current_budget | No daily budget on the platform to move |
no_account_cap | Its account resolved no cap, so there is no ceiling to fund it under |
cannot_zero | Funding it would mean drafting a budget of zero |
batch_limit | Beyond the run's fifty-move limit |
budget_not_at_campaign | Its budget does not live at campaign level |
Alongside them the report carries the cap and where it came from, the sum desired against the sum funded, the funding order itself, and per campaign the phase, the multiplier, the goal that decided it and its priority.
A day, in numbers
A workspace whose daily cap is A$1,000.00, with a movement guardrail of 100 % and two campaigns on one account whose own cap is A$1,200.00.
| Campaign | Phase today | Envelope | Wants | Running at |
|---|---|---|---|---|
| Autumn Drop | Closing, 160 % | A$400.00 | A$640.00 | A$400.00 |
| Evergreen | Hold, 40 % | A$900.00 | A$360.00 | A$500.00 |
Closing funds before hold, so Autumn Drop takes A$640.00 of the A$1,000.00 and Evergreen is funded at A$360.00 out of the A$360.00 remaining — both get what they wanted. The moves are A$400.00 → A$640.00 and A$500.00 → A$360.00; both are inside the 100 % movement clamp and well above the floors, so both are drafted, in one batch against that connection.
Raise Autumn Drop's envelope to A$700.00 and the closing push wants
A$1,120.00. It is funded at A$1,000.00 — the whole workspace cap — and reads
throttled. The row that is actually drafted is A$800.00, not A$1,000.00:
the movement guardrail allows 100 % of what the campaign is running today, so
A$400.00 can at most double in a day, and funding and drafting are two different
numbers whenever the clamp binds. Nothing is left for Evergreen, and funding it
at nothing would mean drafting a budget of zero, which is a pause rather than a
budget move: no row is written for it and the report reads cannot_zero.
Back at the first pair, give Autumn Drop a cost-per-acquisition goal it is
missing with the action propose. It is held at the A$400.00 it is already
running rather than raised to A$640.00, so there is no move to draft and the
report reads goal_missed — the reason it wanted less, kept over the reason
nothing happened.
The record of a run
The allocator is its own ledger, on the audit log:
| Row | When it is written |
|---|---|
planner.run | Once, before any drafting, claiming the day. A second run the same day is refused against it |
planner.drafted | Once per batch that landed, with its correlation id and how many moves it carried |
planner.blocked | Once per connection whose batch the gate refused, with the refusal. The run carries on to the other connections |
planner.run_complete | Last, with what the run actually drafted |
The claim says what the run intended; the terminal row says what it produced. A
day that planned twelve moves and drafted none is a state the claim alone could
never describe, which is why both are written. The report lives on the
planner.run row and in the answer propose_reallocation gives — a batch of
drafts carries the moves, not the reasoning.
Making it hands-off, and turning it off
Autonomy here is a dial, not a switch. The allocator drafts; what clears those
drafts is an approval policy you write over
update_budget, within the amounts and on the accounts you name. Inside those
bounds a batch clears on its own and the record says a rule cleared it; outside
them it waits for a person. Either way it is a change request first, and either
way it is reversible.
Turning it off is the same switch that turned it on. Its drafts are ordinary drafts: anything already at the gate stays there, to approve or reject.
Over MCP
| Route | Capability | Scope |
|---|---|---|
allocation.propose | propose_reallocation | draft |
propose_reallocation runs the same pass on demand. With dryRun it answers the
batch it would draft — the moves, the throttles and the whole report — and
writes nothing at all; without it, it drafts, under the same day ledger as the
scheduled run. Neither form applies anything.
An agent asked to review the pace is best pointed at the pace_review prompt,
which reads the timeline, expands the campaigns that are
off pace and ends at this capability in dry run.
The MCP reference has both.
Phases and envelopes
A ceiling per campaign and dated windows that scale it — launch, hold, closing — so budget follows whichever campaign is in its hot window, under a cap the workspace sets.
Scenarios
Duplicate a plan as a variant, compare the variants on one axis with their totals side by side, and promote the one you want — which materializes it and archives the rest.