Tempio Docs

CLI

tempio is the same scoped surface from a terminal. It is an MCP client: it talks to the MCP server with a key you mint, builds its commands from the route table that server publishes, prints the result envelope the server returns, and exits with a code that says what happened.

It adds nothing of its own. Every command is one call an agent holding the same key could make, every write becomes a change request before it becomes a change, and guardrails and the audit log sit under the tool layer rather than in any of its callers — so a change made from a shell passes exactly what a change made in the app passes.

Install

The binary is tempio, and it needs Node 20 or newer. The publish credential for the npm organisation is still outstanding, so until it exists each release carries the built tarball as an asset and npm i -g ./tempio-cli-<version>.tgz installs the same binary.

npm i -g @tempio/cli        # keep it
npx @tempio/cli --help      # or run it without installing
tempio --version

Sign in

The credential is an MCP key, minted under Settings → MCP with the scopes you choose: read, draft, approve.

tempio login     # prints the URL, then reads the key with no echo
tempio whoami    # the workspace, the scopes, the surface, the key's prefix
tempio logout    # forget this endpoint's key

login takes no --key flag, because a key on a command line is a key in a shell history: it reads the key from the prompt, or from a pipe (tempio login < key.txt). It then verifies the key with one call before storing it, so a key pasted with a newline in it fails at the prompt rather than on your first real command.

The file is $XDG_CONFIG_HOME/tempio/credentials.json — ~/.config/tempio by default, %APPDATA%\tempio on Windows — mode 0600, keyed by the endpoint's origin, so one machine can hold a staging key and a production key at once.

What a call uses, in order:

The keyThe endpoint
--key--endpoint
TEMPIO_API_KEYTEMPIO_ENDPOINT
the credential file's entry for that endpoint's originhttps://app.tempio.ai/api/mcp

No workspace identifier is ever sent and no --organization-id flag exists: the workspace comes off the verified credential. There is no --surface flag either — the CLI always calls tempio_manage, which every key can reach.

The commands

One command per row of the route table, tempio <entity> <action> [flags], generated rather than written, so a capability that lands is a command with no release of its own. A command whose scope your key does not hold is refused by name, with the scope it would need, rather than hidden.

tempio --help                       # every entity, and its actions
tempio <entity> --help              # the actions on one entity
tempio <entity> <action> --help     # the flags, typed, required ones marked
Every tempio command, grouped by entity, with the scope its key must hold and the flags it takes.
EntityCommandScopeFlags
connectiontempio connection listreadno flags
accounttempio account listread--connection-id
tempio account updatedraft--connection-id* --target-entity-id --payload*
campaigntempio campaign listread--ad-account-id --platform
tempio campaign getread--campaign-id*
tempio campaign createdraft--connection-id* --payload*
tempio campaign updatedraft--connection-id* --target-entity-id --operation* --payload*
tempio campaign removedraft--connection-id* --target-entity-id --payload*
ad_grouptempio ad_group listread--parent-id --limit
tempio ad_group createdraft--connection-id* --payload*
tempio ad_group updatedraft--connection-id* --target-entity-id --operation* --payload*
tempio ad_group removedraft--connection-id* --target-entity-id --payload*
adtempio ad listread--parent-id --campaign-id --limit
tempio ad createdraft--connection-id* --payload*
tempio ad updatedraft--connection-id* --target-entity-id --operation* --payload*
tempio ad removedraft--connection-id* --target-entity-id --payload*
creativetempio creative listread--parent-id --limit
tempio creative createdraft--connection-id* --payload*
tempio creative updatedraft--connection-id* --target-entity-id --payload*
keywordtempio keyword listread--parent-id --limit
tempio keyword createdraft--connection-id* --payload*
tempio keyword updatedraft--connection-id* --target-entity-id --payload*
tempio keyword removedraft--connection-id* --target-entity-id --payload*
negative_listtempio negative_list createdraft--connection-id* --payload*
tempio negative_list updatedraft--connection-id* --target-entity-id --payload*
asset_grouptempio asset_group createdraft--connection-id* --payload*
tempio asset_group updatedraft--connection-id* --target-entity-id --payload*
lead_formtempio lead_form createdraft--connection-id* --payload*
mediatempio media listread--ad-account-id --kind --limit
tempio media createdraft--connection-id* --payload*
drafttempio draft listread--correlation-id --status --limit
tempio draft getread--correlation-id
tempio draft createdraft--connection-id* --operations*
tempio draft updatedraft--draft-id* --payload*
tempio draft approveapprove--draft-ids --correlation-id
tempio draft rejectapprove--draft-ids --correlation-id --note
tempio draft revertdraft--draft-id*
plantempio plan listreadno flags
tempio plan getread--plan-id*
tempio plan createdraft--name* --brief --start-date* --end-date* --currency
tempio plan updatedraft--plan-id* --name --brief --start-date --end-date --currency --status
tempio plan materializedraft--plan-id* --promote
plan_itemtempio plan_item createdraft--plan-id* --kind --platform* --name* --objective --budget --start-date* --end-date --ad-account-id --sort-order
tempio plan_item updatedraft--plan-id* --item-id --kind --platform* --name* --objective --budget --start-date* --end-date --ad-account-id --sort-order
tempio plan_item removedraft--plan-id* --item-id*
metricstempio metrics listread--from* --to* --platforms
campaign_metricstempio campaign_metrics listread--from* --to* --platforms
brieftempio brief getread--ad-account-id
researchtempio research searchread--connection-id* --kind* --seeds* --language --geo-target-ids --limit
geotempio geo searchread--connection-id* --query* --country-code --locale --limit
search_termtempio search_term listread--connection-id* --date-range* --campaign-id --ad-group-id --limit
placementtempio placement listread--connection-id* --date-range* --level --campaign-id --ad-group-id --limit
change_eventtempio change_event listread--connection-id* --since* --until* --campaign-id --limit
platform_requesttempio platform_request getread--connection-id* --method* --path* --query --body --description
tempio platform_request mutatedraft--connection-id* --method* --path* --query --body --description*
library_adtempio library_ad getread--ad-id*
tempio library_ad searchread--query --platform --status --format --language --advertiser --min-days --max-days --min-score --min-spend --ids --sort --limit --cursor --seed
library_advertisertempio library_advertiser listread--query --industry --category --tag --source --limit --cursor
tempio library_advertiser getread--advertiser-id*
tempio library_advertiser createdraft--website --name --library-url
tempio library_advertiser searchread--query --industry --category --tag --source --similar-to --limit --cursor
library_watchtempio library_watch listreadno flags
tempio library_watch createdraft--advertiser-id* --watching --alerts --digest
tempio library_watch updatedraft--advertiser-id* --watching --alerts --digest
tempio library_watch removedraft--advertiser-id*
swipetempio swipe listread--collection --limit --cursor
tempio swipe createdraft--ad-id* --collection --note
tempio swipe updatedraft--ad-id* --collection --note
tempio swipe removedraft--ad-id*
swipe_collectiontempio swipe_collection listread--collection --limit --cursor
tempio swipe_collection createdraft--ad-id* --collection --note
tempio swipe_collection updatedraft--ad-id* --collection --note
tempio swipe_collection removedraftA swipe collection is not removed on its own: it exists while ads are saved into it. Remove the ads with update_swipe and `remove: true`, one adId at a time.
playbooktempio playbook listread--platforms
tempio playbook getread--slug* --section
guardrailtempio guardrail listread--connection-id
tempio guardrail getread--ad-account-id*
approval_chaintempio approval_chain listreadno flags
tempio approval_chain getread--chain-id
connection_permissiontempio connection_permission listread--connection-id
allocationtempio allocation proposedraft--dry-run
timelinetempio timeline getread--from --to --platforms --ad-account-ids --plan-id
pacingtempio pacing getread--campaign-id --plan-item-id
phasetempio phase listread--campaign-id --plan-item-id
tempio phase createdraft--campaign-id --plan-item-id --kind* --label --start-date* --end-date* --multiplier-pct* --note
tempio phase updatedraft--campaign-id --plan-item-id --id --kind* --label --start-date* --end-date* --multiplier-pct* --note
tempio phase removedraft--phase-id*
envelopetempio envelope listread--campaign-ids --plan-item-ids
goaltempio goal createdraft--campaign-id --plan-item-id --metric* --direction* --target* --window-days --action --note
tempio goal updatedraft--campaign-id --plan-item-id --id --metric* --direction* --target* --window-days --action --note
tempio goal removedraft--goal-id*
brand_kittempio brand_kit getread--ad-account-id
tempio brand_kit updatedraft--ad-account-id --name --logo-media-asset-id --logo-blob-url --roles --typography --voice --compliance-line --forbidden-words --products --source-url
tempio brand_kit scraperead--url*
presettempio preset listread--kind
creative_assettempio creative_asset listread--preset-key --status --limit
tempio creative_asset createdraft--preset-key* --brand-kit-id --fields* --product-labels --reference --aspects --quantity --verb --instructions --model-id
tempio creative_asset resizedraft--asset-id* --aspect*
tempio creative_asset registerdraft--asset-id* --aspect* --ad-account-id*
creative_batchtempio creative_batch getread--batch-id*
lane_colourtempio lane_colour updatedraft--campaign-ids --plan-item-ids --colour*
lane_ordertempio lane_order updatedraft--lane* --before --after
plan_dependencytempio plan_dependency createdraft--predecessor* --successor*
tempio plan_dependency removedraft--dependency-id --predecessor --successor
key_datetempio key_date listread--from --to --region
tempio key_date createdraft--name* --start-date* --end-date --recurs --colour
tempio key_date updatedraft--id --name* --start-date* --end-date --recurs --colour
tempio key_date removedraft--id*

108 commands over 46 entities. A flag marked * is required. Every command also takes --endpoint, --key, --output and --json.

Flags are the parameters themselves, kebab-cased and typed: a string, a number, a boolean (--watching and --no-watching), or JSON for an object or an array. --json '<object>' passes the whole parameter object at once and is merged under the flags, so a flag wins over it.

A write row takes the form the route documents rather than the batch its tool takes: --connection-id, --target-entity-id, --payload, and --operation where the row names more than one. The create row of the draft entity is the n-ary form instead: --json '{…}' carries one whole batch, with dependsOn indices between its entries.

A parameter a route supplies itself is not offered as a flag at all, on this page or in the binary. Each row of the route table publishes the parameters it reads and the ones it sets itself, and both readers derive their flags from those two lists, so a flag printed here is a flag the binary takes. tempio help manage <entity> <action> --full is the authority on what a row takes, and it is the server answering.

tempio help is that server-side catalogue, not a second copy of it:

tempio help                                   # what this workspace is
tempio help manage <entity> <action> --full   # the parameters of one row
tempio help --q budget                        # search before concluding it is missing

Output

Stdout carries the answer and nothing else. It is JSON when stdout is not a terminal or when --json is given, and a table when it is a terminal; --output json and --output table decide it outright either way.

  • Money is an integer in the minor units of the currency the answer reports, printed with the code beside it and divided by nothing. 1234500 AUD is $12,345.00. Metrics is the rule this follows.
  • A ratio whose denominator was zero is null in JSON and — in the table. It is never 0.
  • The deep link to a record is the last column of the table and a field in the JSON, never truncated.
  • A write prints Drafted — review at … and never "applied". Approval is a separate act — yours, or a rule you wrote — and --wait below is what earns the other word.

Colour appears only on a terminal, never carries meaning on its own, and NO_COLOR turns it off.

Warnings, on stderr

Every warning on a result is printed to stderr, one line each, in both output modes, as [severity] code: message. They are never left buried in a body nobody is reading: a converted total is an estimate, a figure from a connection that has not synced carries when it was last refreshed, and a blocking warning means stop rather than retry. The warning classes are listed on the MCP reference. In table mode the scope of the answer — its currency, time zone and date range — is one more stderr line, so stdout stays pipeable.

Exit codes

A guardrail refusing a change, a connection that is missing and a network that is down are three different outcomes, and they exit as three different things.

Every exit code tempio can end with, the server codes that produce it, whether the same call is worth repeating, and what the outcome means.
ExitCodeRetry?What it means
1adapternoThe ad platform refused the call, and its reason is the message.
apply_failednoThe change was approved but the platform did not apply it; the draft records what came back.
invalid_statenoThe thing you named cannot do this in the state it is in.
unknownnoThe call failed for a reason this table does not name.
2invalid_payloadnoThe call was missing something or carried the wrong shape; the message names the field.
3unauthorizednoNo credential was sent, or the server refused the one that was.
4forbiddennoThe credential does not hold the scope this call needs, or you do not hold the permission.
5not_foundnoNothing matches what you named, here or on the platform.
6guardrail_blockednoA guardrail refused the change before it reached the platform.
7plan_limitnoYour plan's allowance for this is already used up.
8connect_cancellednoThe connection was never finished because someone backed out of the platform’s consent screen.
platform_unavailableyesThe ad platform cannot be reached from here right now.
rate_limitedyesThis credential has made too many calls this minute; wait for the window to reset.
unavailableyesThe route is named in the table but no tool answers it yet; the message names the step that lands it.
9networkyesThe call did not complete because the network failed.

0 is every command that succeeded with nothing blocking in its warnings. A blocking warning riding along with an answer that otherwise succeeded is the gate refusing, so it exits 6 rather than carrying a number of its own. The stderr line says "retry" exactly where this table does.

TEMPIO_DEBUG=1 adds the underlying cause to the line a network failure prints. It is a debugging fact rather than a flag.

--wait

A draft is approved and applied moments later, so the answer to an approval is "claimed", not "applied". --wait — on the approve and create rows of the draft entity — reads the batch back every two seconds until every row in it has stopped moving, or until --timeout seconds have passed (120 by default). The exit code then follows what it last read: every row applied is 0, and partial, failed or a timeout is 1.

Three worked scripts

A morning read, piped. Output is JSON on a pipe, so jq needs no flag:

tempio campaign_metrics list --from 2026-09-01 --to 2026-09-13 \
  | jq '.data.rows[] | select(.spend > 100000) | {name, spend, roas}'

A pause drafted from cron, with the exit code read. 6 is the gate refusing, which is an answer rather than an outage:

#!/bin/sh
tempio campaign update \
  --connection-id "$CONNECTION" \
  --target-entity-id "$CAMPAIGN" \
  --operation update_status \
  --payload '{"status":"paused"}'
case $? in
  0) echo "drafted; the review link is on stdout" ;;
  6) echo "a guardrail refused it — nothing was drafted"; exit 0 ;;
  8) echo "come back later"; exit 75 ;;
  *) exit 1 ;;
esac

A plan materialised, then watched. The first call drafts the whole plan as one batch; the second approves that batch and waits for the platforms:

tempio plan materialize --plan-id "$PLAN" --output json > batch.json
tempio draft approve \
  --correlation-id "$(jq -r '.data.correlationIds[0]' batch.json)" \
  --wait --timeout 300

A key that holds draft but not approve runs the first of those two and is refused by name on the second, which is the shape a build server should have.