ai.oz0/ai-spend
For: tenant administrators and plugin users.
ai.oz0/ai-spend imports company AI spending that did not pass through Orchestrator Zero. It reads Anthropic and OpenAI admin cost and usage reports on your nodes with the organisation's admin keys.
The plugin records outside spend by day, provider, model and team alongside gateway spending. Its only outbound requests are to those two admin APIs.
| Function | What it does |
|---|---|
oz0_ai_spend.import_spend | days (1 to 31, 7 by default) or start and end, and dry_run: reads both providers' cost reports, and their usage reports for tokens, for whole UTC days, maps each workspace or project to a team, and hands the rows to Orchestrator Zero. Never today, which is not over. |
The oz0-ai-spend-import flow calls it, and the plugin ships a routine that runs the flow once a day for the last
seven days, so a provider's late correction of a recent day is picked up and a day missed while a node was away is
imported the next day. Importing the same days again adds nothing.
Install
oz0 plugin install hub:ai.oz0/ai-spend --accept-provides outside-spend
printf '%s' "$ANTHROPIC_ADMIN_KEY" | oz0 secret set AI_SPEND_ANTHROPIC_ADMIN_KEY
printf '%s' "$OPENAI_ADMIN_KEY" | oz0 secret set AI_SPEND_OPENAI_ADMIN_KEY
oz0 setting set AI_SPEND_TEAMS 'anthropic:Research = research; openai:Growth = growth; openai:* = platform'
oz0 routine save -f plugins/ai-spend/routines/oz0-ai-spend-daily.yaml
oz0 routine run ai-spend-daily --wait
oz0 usage outside
--accept-provides outside-spendis a tenant admin's grant: the plugin may record spend that belongs to no job. An install without it is refused and says so. The grant is audited (plugin.provides.granted), shown byoz0 plugin list, taken back withoz0 plugin revoke-provides ai-spend outside-spend, and dropped when the plugin is removed. See the manifest's provides.- The admin keys are an Anthropic Admin API key (
sk-ant-admin..., made by an organization admin in the Claude Console) and an OpenAI admin key (made in the organization settings). Set one or both; a provider without a key is skipped. They are tenant secrets bound by credential injection: the plugin's process holds placeholders, and the node's egress proxy puts the key on GET requests toapi.anthropic.com/v1/organizationsandapi.openai.com/v1/organizationalone. AI_SPEND_TEAMSmaps workspaces and projects to teams: one rule per line or separated by;,<provider>:<workspace or project name or ID> = <team>,*for any. Anthropic's default workspace isdefault. The first rule that matches wins; spend no rule maps is the tenant's, shown as unassigned.- The routine in
routines/oz0-ai-spend-daily.yamlfires at 04:20 UTC with up to 15 minutes of jitter. Set itsowner_teamto the team that owns spend reporting before you save it.
AI_SPEND_ANTHROPIC_URL and AI_SPEND_OPENAI_URL point the plugin at a proxy of your own (https only); the keys still
go only to the providers' hosts, so a proxy must forward the request with the injected header to them.
What it reads, and what it never reads
- The reports are asked per workspace (Anthropic) or project (OpenAI) and model, never per user, account, service account or API key, so no figure about a person ever reaches the plugin. Workspace and project names stay in the plugin; the rows carry the provider's ID, which no view shows.
- Cost comes from the cost reports only. The usage reports lend input and output tokens to the same day, workspace and model; no amount is estimated from tokens and a price list.
- Currencies are kept as the provider gives them, and never converted.
- A team figure goes through works-council mode: a team of fewer people than the threshold is summed into one row that names no team.
When it fails
| What it says | Why, and what to do |
|---|---|
the anthropic admin key was refused (401) | The key expired, was revoked or is not an admin key: set a new one with oz0 secret set AI_SPEND_ANTHROPIC_ADMIN_KEY. The other provider's rows are still imported. |
tenant ... has not granted plugin ai-spend outside-spend | The grant was revoked or never given: install again with --accept-provides outside-spend. |
... is not on the egress allowlist | AI_SPEND_*_URL names a host that is neither the provider's nor on the tenant's list: allow it with oz0 tenant egress. |
more than 500 rows; import fewer days at a time | One call carries at most 500 rows: import a shorter range (days, or start and end). |
A fire that imports nothing fails, so a routine that keeps failing pauses itself and says why (routines).
Tests
make test-plugins reads the providers' admin APIs from scripts/fakellm (paging, amounts, currencies, partial days,
the mapping, an expired key, and that nothing is asked per person), and scripts/e2e-examples.sh installs the plugin
with its keys injected, runs its routine twice against the fakes and checks the rows by team.
The import asks by default
The plugin's suggested policy asks a person before each import_spend ("the plugin asks before it writes the
tenant's outside spend"). The daily routine runs unattended, so a tenant that saves it switches the function once, with
a reason: oz0 plugin policy ai-spend --set oz0_ai_spend.import_spend=allow --reason "the daily import runs unattended".
Microsoft Teams
The verified plugin ai.oz0/teams - Microsoft Teams as the front door to your agents, with answers, questions and approvals as cards in the thread.
ai.oz0/a2a-remote
Outside agents that speak the A2A protocol, as agents of your tenant under its budgets, approvals, kill switches and audit log; and the AgentCore and Foundry presets on it.