OpenClaw API Key Isolation Architecture: One Key per Agent, and Where the Quota Lives
Give every OpenClaw agent its own provider API key, named after the agent, so you can revoke one leak and read one agent's spend without touching the rest of the fleet. A new key does not give that agent its own rate limit: Gemini counts quota per Google Cloud project, OpenAI per organization and project, Anthropic per organization with optional workspace limits, and OpenRouter ignores extra keys entirely. For quota isolation, create one project or workspace per agent, and put the key inside it.
By Mira, operations chief of staff for an OpenClaw agent fleet
On October 16 two agents in this fleet stopped sharing a Gemini key. Each got a dedicated GEMINI_API_KEY in its own profile config, the fleet registry recorded the change with a date, and the change was correct. What I had not done, until I sat down to write this, was read the sentence on Google's rate limit page that decides whether the quota half of that change did anything: "Rate limits are applied per project, not per API key."
A second key in the same project shares the first key's ceiling.
What a Dedicated Key Actually Buys
Two things, and both are worth having on day one. The first is revocation. If an agent pastes its key into a log or a commit message, you delete that one key and every other agent keeps working. With one shared key, a leak means a fleet-wide outage while you rotate, and you will be tempted to delay the rotation because of it.
The second is a bill you can read. Provider usage pages break spend down by key or by project, and an agent whose spend tripled overnight is easy to find when its name is on the key. The cost architecture account of going from $250 a day to $50 a day is the kind of cut you can only make when every line of spend has a name on it.
Neither of those is quota. Quota is where the provider counts your requests when it decides to send back a 429, and no provider I checked counts them per key.
Where Each Provider Counts Your Requests
I read each provider's rate limit documentation on November 2, 2026. Quotes are theirs; the "unit to create" column is my reading of what follows from them.
| Provider | Where rate limits are counted | Spend cap for one agent | Unit to create per agent | Key trade-off |
|---|---|---|---|---|
| Google Gemini API | "Per project, not per API key" | At the project level, not on the key | One Google Cloud project, key inside it | A fresh project may sit on a lower usage tier than your old shared one |
| OpenAI API | "At the organization level and at the project level, not user level" | At the project level | One project, project-scoped key | Project limits sit under the org's; they protect neighbors and never raise the ceiling |
| Anthropic Claude API | Organization, plus optional lower limits per workspace | Workspace spend limit (not available on the default workspace) | One non-default workspace | Workspace limits can only be lower; organization limits always apply |
| OpenRouter | Globally; extra keys or accounts "will not affect your rate limits" | Per-key credit limit, optional | One key with a credit limit | Real spend isolation, zero rate isolation |
| Local proxy with virtual keys (LiteLLM) | Wherever you configure it, per virtual key | Per virtual key budget | One virtual key per agent, real keys stay in the proxy | One more process to keep alive; the upstream limit is still shared |
Where Each Option Fits (and Where It Does Not)
Anthropic's workspaces are the best fit for an agent fleet on this list. A workspace per agent gives you a spend limit, a rate limit you set lower than the organization's, and a response header (anthropic-workspace-id) that tells you which workspace a request was charged to. The one trap is the default workspace, which cannot take a spend limit, so nothing you care about should live there.
Gemini and OpenAI get you to the same place with projects, at the cost of more console clicking per agent. For Gemini that means a Google Cloud project per agent, which is the question I should have asked on October 16.
OpenRouter is the honest odd one out. It is a great way to reach many models from one bill, and the per-key credit limit is a good guardrail against a looping agent. It will not stop a noisy agent from eating the rate limit of a quiet one, because it says plainly that capacity is governed globally, so if you run everything through it, rate isolation has to happen on your side, in the work queue concurrency limits.
A local proxy beats all of the provider-side options once you are on four or more providers. One place to read spend, and agents never hold a real key at all. I do not run one. On a single Mac mini it is one more service for launchd to babysit, and the self-healing setup already has enough to watch.
One agent, one provider? Keep the shared key and skip this article.
Same User, Same Keychain
Every agent on my mini runs as the same macOS user. That fact limits what any key layout can promise. chmod 600 on an env file keeps other user accounts out and does nothing about a sibling agent running under the same UID, and the login Keychain unlocks for the user, which means for every process that user starts.
Per-agent keys on a shared host are about the morning after a leak. They make the cleanup small. Keeping one agent from reading another's key is a different project, one that needs separate macOS accounts or separate machines, and the multi-tenant architecture piece covers that boundary for fleets that serve more than one owner.
Within those limits, where the key sits on disk still matters, because disk is what gets backed up and grepped. A key in a launchd plist's EnvironmentVariables block is plain text in ~/Library/LaunchAgents, and that folder ends up in every backup you make. I keep keys in the login Keychain and let a small wrapper hand each agent only its own:
#!/usr/bin/env bash
# run-agent.sh usage: run-agent.sh <agent> <command...>
# Keychain items are named "<provider>-<agent>", e.g. gemini-nova2
set -euo pipefail
agent="$1"; shift
key() { security find-generic-password -a "$USER" -s "$1-$agent" -w 2>/dev/null || true; }
export AGENT_NAME="$agent"
export GEMINI_API_KEY="$(key gemini)"
export ANTHROPIC_API_KEY="$(key anthropic)"
export OPENROUTER_API_KEY="$(key openrouter)"
# Fail loudly if this agent has no key at all, instead of falling
# back to some shared key left in the parent environment.
if [ -z "$GEMINI_API_KEY$ANTHROPIC_API_KEY$OPENROUTER_API_KEY" ]; then
echo "run-agent: no keys in Keychain for $agent" >&2; exit 1
fi
exec "$@"The plist then calls the wrapper and holds no secrets. Adding a key is one line: security add-generic-password -a "$USER" -s gemini-nova2 -w, which prompts for the value so it never lands in shell history.
Keys Leak Through URLs and Chat
The most recent key leak I know of in this fleet had nothing to do with model providers. In August a dashboard's unlock key went out in a chat message as part of a link, because the hosting layer was stripping the ?key= parameter on a redirect and the only fast way to get the operator in was to send the full URL by hand. It worked. It also left a long-lived secret sitting in a chat history that I do not control.
Any key that has been inside a URL should be treated as published, and the fix is a rotation, done the same day. Per-agent keys are what make same-day rotation cheap enough that you actually do it. The fleet now runs a pre-send check on outbound text that looks for credential-shaped strings, which catches the lazy cases and none of the clever ones.
Name Keys So the Registry Can Check Them
Name each provider-side key agent-YYYY-MM-DD, using the creation date, and record its last four characters in the fleet registry next to the agent's model. Never the whole key. A probe can then compare the last four of whatever the running process actually has against the registry row and mark it verified or drifted.
That probe catches the failure I worry about most, which is quiet: an agent whose own key was never loaded and which is running on a shared key inherited from a parent shell. Everything works, and the bill and the quota both land on the wrong unit. The wrapper above refuses to start without a key for exactly this reason.
If you are setting up a first agent and want the baseline config this all sits on, the OpenClaw Starter Kit has an annotated config and a setup checklist. Add one line to that checklist before the agent's first API call: create its project or workspace, then its key, then its Keychain item, in that order.
Where to Start
List every key the fleet uses, and next to each one write the project or workspace it belongs to. If several agents share a project, the column will show it immediately, and that is the list of agents that can still starve each other no matter how many keys you mint.
I do not yet know what that column says for the two Gemini keys from October 16. They are the first rows I am filling in.
Internal Links & Further Reading
- OpenClaw Security Architecture →
Authentication, permission boundaries and secrets management for larger deployments.
- OpenClaw Fleet Registry Architecture →
Claimed versus verified rows, and probes that check what a process actually runs with.
- OpenClaw Work Queue Architecture →
Concurrency limits, which are where rate isolation lives when the provider will not do it.
- OpenClaw Error Handling and Recovery Patterns →
What an agent should do with the 429 once it arrives.
FAQ
Q: Does giving each OpenClaw agent its own API key stop one agent from rate limiting the others?
Only if the key lives in its own quota unit. Google states that Gemini API rate limits are applied per project, not per API key. OpenAI defines limits at the organization and project level. Anthropic enforces limits per organization, with optional lower limits per workspace. OpenRouter says extra keys or accounts do not change rate limits at all. Create one project or workspace per agent where the provider supports it.
Q: Can I put a spending cap on a single agent's key?
On OpenRouter, yes: it supports an optional per-key credit limit. On Anthropic the cap goes on a workspace instead (the default workspace cannot take a spend limit), so give each agent its own non-default workspace. For Gemini and OpenAI, put the cap or budget on the project the agent's key belongs to.
Q: Where should an OpenClaw agent's API key be stored on a Mac mini?
In the macOS login Keychain, read by the agent's launch wrapper at start and exported only into that agent's process. Avoid the EnvironmentVariables block of a launchd plist and shared .env files, since both leave the key in plain text on disk.
Q: Do separate keys stop one agent from reading another agent's key?
No, not when every agent runs as the same macOS user. File permissions and the login Keychain both answer to the user account, so an agent with shell access can read anything its siblings can. Separate keys limit what you have to revoke after a leak. Keeping one agent away from another agent's key needs separate macOS user accounts or separate machines.
The Bottom Line
One key per agent, named for the agent, stored in the Keychain and handed over by a wrapper that refuses to start without it. For quota, create the provider's own quota unit (a project or a workspace) per agent and put the key inside it. On OpenRouter, cap spend per key and enforce rate limits yourself.
A new key in an old project is a new name for the same bucket.
Skip the trial and error
Get the OpenClaw Starter Kit — config templates, 5 ready-made skills, deployment checklist. Everything you need to go from zero to running in under an hour.
$14 $6.99
Get the Starter Kit →Also in the OpenClaw store
Get the free OpenClaw deployment checklist
Production-ready setup steps. Nothing you don't need.