Skip to Content
QuickstartGovern Your Claude Code Fleet

Govern Your Claude Code Fleet

Your team is running coding agents. You can see one number: the provider bill. You cannot see which developer it came from, which repo they were working in, or which agent burned it.

One command per developer fixes that.

npm install -g @curate-me/cli curate login curate init claude-code

That mints an API key attributed to the developer running it, points Claude Code at the gateway, and makes one real governed call to prove the path works. Their next Claude Code session shows up under Gateway → Harnesses.

Attribution is descriptive metadata. It records who a key belongs to; it never grants or restricts access. Authorization stays with the org and the key’s scopes.

What curate init claude-code does

  1. Reads git config user.email and your origin remote, so the key carries {developer_email, harness, repo}.

  2. Mints a per-developer key through the gateway API.

  3. Merges two variables into ~/.claude/settings.json:

    { "env": { "ANTHROPIC_BASE_URL": "https://api.curate-me.ai/v1/anthropic", "ANTHROPIC_AUTH_TOKEN": "cm_sk_..." } }

    Your existing settings are preserved, the previous file is backed up to settings.json.curate-backup, and the result is written 0600 because it now holds a key.

  4. Makes a governed call over that exact path. If the key is rejected, nothing is written — you don’t end up with a Claude Code pointed at a gateway it can’t authenticate to.

Claude Code sends the token as Authorization: Bearer and performs no OAuth handshake when a gateway credential is set, so the key is the only credential in play on that machine.

Other harnesses

Codex and OpenCode speak the OpenAI protocol. We print their configuration rather than writing their config files, because their schemas are not stable enough for us to promise we won’t break an existing setup.

curate init codex # export OPENAI_BASE_URL=https://api.curate-me.ai/v1/openai # export OPENAI_API_KEY=cm_sk_...

Reading the Harnesses page

Gateway → Harnesses groups spend three ways: by developer, by harness, by repo. Switch dimension at the top; pick a 7, 30, or 90 day window.

One row is always worth reading first: unattributed.

That is spend the gateway recorded but cannot tie to a developer — keys minted before attribution existed, keys deliberately left unattributed, keys deleted since the spend happened, and autopilot runs, which carry no key at all. We show it rather than hiding it, so the rows on the page always add up to your real gateway total. An Attributed figure below 100% tells you how much of your bill still has no name on it.

Do not hand developers a shared key, and do not hand them a provider token. A shared credential authenticates as one identity, so every request lands in a single bucket and per-developer budgets have nothing to attach to.

Attributing keys that already exist

You don’t have to rotate a key to attribute it:

curl -X PATCH https://api.curate-me.ai/api/v1/platform/api-keys/$KEY_ID/attribution \ -H "Authorization: Bearer $DASHBOARD_TOKEN" \ -H "Content-Type: application/json" \ -d '{"attribution": {"developer_email": "dana@acme.com", "harness": "claude-code"}}'

Attribution survives rotation, so a rotated key keeps its owner.

Send {"attribution": null} to clear it. Requires the api_keys:update permission (owner or admin).

Per-developer budgets

Attribution answers who spent it. Per-key spend caps stop it. Set daily_spend_cap_usd or monthly_spend_cap_usd when you create the key, and the gateway’s budget stage enforces it before the request reaches the provider.

curl -X POST https://api.curate-me.ai/api/v1/platform/api-keys \ -H "Authorization: Bearer $DASHBOARD_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "claude-code — dana", "daily_spend_cap_usd": 25, "attribution": {"developer_email": "dana@acme.com", "harness": "claude-code"} }'

Query the rollup directly

curl "https://api.curate-me.ai/gateway/admin/usage/by-attribution?group_by=developer_email&days=7" \ -H "X-CM-API-Key: $CM_API_KEY"
{ "org_id": "org_...", "group_by": "developer_email", "total_requests": 2808, "total_cost": 0.02714, "groups": [ { "value": "dana@acme.com", "request_count": 1, "total_cost": 0.00006, "key_count": 1 }, { "value": "unattributed", "request_count": 2807, "total_cost": 0.02708, "key_count": 1 } ] }

group_by accepts developer_email, harness, or repo. The group totals always sum to total_cost.

Troubleshooting

“Minting a per-developer key needs a dashboard session.” curate login with a dashboard token. A cm_sk_ gateway key can proxy requests but cannot create other keys.

“The gateway has no upstream provider key for this org.” The harness is configured correctly; the gateway has nothing to call. Add your provider key under Settings → Providers.

Everything shows as unattributed. Those keys were minted without attribution. Attribute them with the PATCH call above, or re-run curate init claude-code to mint a fresh one.