Claude Code for teams: what changes when agents are multi-tenant
Your agent works great when it has one user. The day it has ten thousand, you're suddenly building orgs, roles, audit, quotas, impersonation, and webhooks. Here's the list of what you need, and the pattern we borrowed from Stripe to get it right.
๐ค Your agent has one user. Now it has ten thousand.
Claude Code, Cursor, OpenClaw, Antigravity: the autonomous coding agents of 2025 and 2026 got very good, very fast. The shape of the product is the same: one developer, one laptop, one agent. Credentials are the developer's credentials. Filesystem is the developer's filesystem. Logs are the developer's terminal.
That shape works as long as the agent has exactly one user. The moment you decide to ship that capability to an actual team (your own team using a shared internal tool, or your users embedding an agent in a SaaS you run) you discover a second product hiding inside the first one.
The second product has organizations, roles, invitations, quotas, audit logs, impersonation, API keys, idempotency, webhooks, versioning, and a few more things. It took Stripe a decade to get its version of that product right. There's a good chance you don't want to build all of it again.
This post is about what changes when an agent moves from "one user" to "many users", and what patterns make the transition not terrible.
๐ The seven things you'll build (and probably shouldn't)
The gap between a personal agent and a team agent is a set of features that look optional until they aren't. Here's the list in the order you'll regret not having them.
1. Organizations and membership
The moment two people share an agent, there's an implicit organization wrapped around it. Someone is the owner. Someone is an admin. Someone is a member. Someone needs to be removed when they leave. Someone needs to be invited, with an email, via a link that expires, against a role.
You'll write this layer. It takes two weeks.
2. Roles and permissions, the real ones
Three roles (owner / admin / member) is the minimum that survives contact with users. It is not enough for a platform. Real RBAC has verbs (read, write, delete, invite, billing) against resources (agents, runs, models, webhooks, api_keys, connections). You end up with thirty to a hundred permission combinations.
At Appstrate we ended up with 78. It's not a design flourish; it's the number you need if you don't want the first enterprise evaluator to laugh you out of the demo.
3. API keys that are scoped, not bearer-to-root
A single API key that does everything is fine on day one and a security incident on day 300. Real API keys are scoped (this key can read runs but not create agents), attributable (who created it, when, last used when), revocable instantly, and rate-limited per key.
They also need a sensible prefix (ask_ in Appstrate's case) so that your detection tooling can grep for them in public repos.
4. Audit logs on the trusted side
When a user of a user of your platform exfiltrates data, the logs in the agent process are not admissible. You need audit trails on the platform side, written by the runtime, not by anything the agent can influence. Who ran what, on behalf of whom, at what time, from which IP, with which outcome. Stored for long enough that compliance signs off.
5. Quotas, rate limits, and a kill switch
One user can run an agent as many times as they want on their own machine. On a shared platform, that's a bill and a DoS vector. You need per-org concurrency caps, per-minute rate limits, per-day budget ceilings, and a kill switch to cancel in-flight runs when something goes wrong.
The one that catches teams off guard: a shared kill switch for "cancel every run across the platform right now", because one day you'll deploy a bad agent version and need it.
6. Impersonation for support
Your first support ticket will be "my agent didn't work" and you will not be able to reproduce it without becoming that user for five minutes. Every mature multi-tenant system has impersonation. The ones that do it right have audit trails on impersonation itself (who impersonated whom, when, for how long).
7. Webhooks, idempotency, versioning
Anything long-running and multi-tenant needs an async callback story. Anything with retries needs idempotency keys or duplicated actions become the norm. Anything with a public API needs a versioning strategy so that breaking changes don't break downstream.
None of these are optional if you want to be used in production. All of them are annoying to build correctly.
๐ญ Dashboard users vs end-users: the Stripe distinction
Here's the subtle one. When you make your agent multi-tenant, you have to deal with two kinds of users, and confusing them is the single most common cause of a broken platform.
Dashboard users are your users. Your team. The developers and admins who log into the platform directly, configure agents, look at logs, manage API keys. They have passwords. They have 2FA. They see a UI. They belong to organizations.
End-users are the users of the thing you built on top of the platform. They never log into your agent dashboard. They live in your product. Their name is in your customer table. They have an externalId you assigned them. They connect their own Gmail, their own Notion, their own GitHub to the agents that run on their behalf.
Stripe figured this out early. User in the dashboard is a person on your team. Customer is a person who pays you. Two tables, two models, two lifecycles, two sets of rules. The same separation has to exist in an agent platform:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Organization (your company) โ
โ โ
โ Dashboard users โโโโ the people on your team โ
โ โโโโโโโโโโโโโโโโ password, role, dashboard login โ
โ โ
โ Application โโโโโโโโ a product you ship โ
โ โโโโโโโโโโโโโโโโ your SaaS, your internal tool โ
โ โ
โ End-users โโโโ the users of your product โ
โ โโโโโโโโโโโโโ externalId, metadata, their credentials โ
โ their runs, their webhooks โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
When you don't make this split, you end up with one of two bad outcomes. Either end-users can see dashboard data (a breach), or dashboard users inherit end-user concerns and your role system collapses under its own weight.
In Appstrate, dashboard users live in the users table, end-users live in end_users, and the API keys that create end-user runs carry an Appstrate-User: eu_โฆ header, the same shape as Stripe's Stripe-Account header, for exactly the same reason.
๐๏ธ Impersonation, done properly
The pattern is the same as the rest: borrow from payments, don't reinvent.
POST /api/runs
Authorization: Bearer ask_live_โฆ
Appstrate-User: eu_01HZXYโฆ
Idempotency-Key: run-2026-03-28-abc123
Content-Type: application/json
{ "agentId": "agent_inbox_triage", "input": { โฆ } }
Four things worth noting in that request, because each one is a lesson from running this wrong the first time:
Appstrate-Useris rejected on cookie auth. Dashboard sessions can't impersonate; only API key auth can, and the API key's application has to match the end-user's. This stops the most common support mistake ("I forgot which user I was logged in as") from becoming an incident.Idempotency-Keymakes retries safe. The platform stores the response for 24 hours. A duplicate key with a matching body returns the cached result; a duplicate key with a different body gets a422. This is how you run an agent from a retrying cron without double-billing.- The run inherits the end-user's connections, not the dashboard user's. When the agent calls Gmail via the broker, it uses
eu_01HZXY's token, not yours. This is the single most important piece of wiring: who is the agent acting for, right now? - Every impersonation emits an audit record: the request ID, the API key ID, the impersonated end-user ID, the IP, the user agent. The log lives on the platform, not in the agent process.
You can build all of this in a quarter. You shouldn't, or rather, you should, but only the parts specific to your product. The multi-tenant plumbing is the same for every team building on top of agents.
๐งฑ What "Claude Code for teams" actually looks like
The phrase is a shorthand. It's not a literal port of Claude Code; it's a pattern.
A single-user coding agent is a personality. A team agent is a platform around that personality. You get:
- The same prompt that worked on your laptop, running on behalf of your teammates.
- The same agent package (prompt + schema + skills + tools), versioned and installable across applications.
- Roles that reflect who's allowed to run what.
- Rate limits so that one user can't eat the org's budget.
- Audit logs so that your security review passes.
- API keys so that your CI can trigger runs.
- Webhooks so that your product can react to runs finishing.
- Impersonation so that your support can reproduce the issue.
A team agent isn't a better Claude Code. It's Claude Code wrapped in a hundred boring pieces of infrastructure that every multi-tenant product eventually needs. The reason a runtime platform exists is to ship those hundred pieces once, correctly, and let the agent writers focus on the prompt.
๐ Related
Other posts
- What is an agent runtime platform?: the category-level framing.
- Why personal agents leak credentials: the security side of multi-tenant agents.
- Your agents, your infrastructure: the case for self-hosted runtimes.
- The agent runtime landscape in 2026: how multi-tenant stacks up across the five players.
Appstrate docs
- Applications: the application model.
- End-users: the Stripe-style end-user model.
- API keys: scoped, attributable, revocable.
- Webhooks: the async callback story.
- Organizations: roles, members, invitations.