Serve many customers
An end user is your customer’s user, named by the user_id your backend passes.
You need: a deployed runtime (here support-agent), a backend that starts
tasks (Run tasks from your backend), and owner or
admin role.
Choose the split
| The customer needs | Use |
|---|---|
| Only its own settings, playbook, or prompt variant | One shared runtime with per-task metadata (steps 1–3) |
| Its own credentials, connector, judges, experiment, or cost report | A runtime per customer (step 4) |
| Teammates who must not see each other’s customers | Role member, with tasks tagged per customer (sharing). Owners and admins see every project; only a separate organization separates them. |
1. Name the end user on every task
Take the ID from your server session. Identity tags group end users by customer.
const runner = await client.runtimes("support-agent").run({
identity: { user_id: user.id, tags: ["customer:acme"] },
});Memory and connections follow the identity (ownership). Tags apply only when the member is first created, and only tags the agent member holds: an owner or admin tags the agent member first.
2. Pass per-task configuration
Task metadata reaches the agent as INTROSPECTION_TASK_METADATA_JSON.
const handle = await runner.tasks.start({
prompt,
metadata: { customer: "acme", playbook: "acme-v3", region: "eu" },
tags: ["customer:acme"],
});Read $INTROSPECTION_TASK_METADATA_JSON first. Follow the playbook in
/workspace/files/playbooks/<playbook>.md.Task tags are access-bearing: any member whose tags intersect them can read
and write the task. List a customer’s tasks with runner.tasks.list({ tag: "customer:acme" }).
3. Share customer-wide files
introspection shares create --resource-type file --resource-id <file-id> --tag customer:acmeEvery Acme end user may read it; the agent gets it when your backend attaches it by ID (Sharing).
4. Onboard a customer with its own runtime
-
Add a manifest from the same recipe, here for Acme:
.introspection/support-acme.yamlname: support-acme path: apps/support-agent -
Commit and push it to
main. -
Create the runtime:
introspection runtimes create --manifest .introspection/support-acme.yaml -
Bind the customer’s own credentials and servers:
introspection bindings credentials create --name CRM_TOKEN --from-env CRM_TOKEN -r support-acme introspection bindings mcp connect --mcp-server-id crm --endpoint-url <crm-url> \ --header 'Authorization=Bearer ${CRM_TOKEN}' -r support-acme
Bindings, judges, metrics, and experiments are per runtime. To ship to one customer first, pin production on the others (Test before production).
Verify
introspection conversations list --filter owner_key=user:<id> -o table
introspection members get user:<id>Expect only that end user’s conversations and one customer member.
Or ask your agent: “Onboard Acme with its own support-agent runtime.”
Limits
| Not supported | Do this instead |
|---|---|
| An experiment for one customer in a shared runtime | A runtime per design partner. |
| A different connector per task in one runtime | Per-user Pipedream connections, or a runtime per customer. |
| Cost or metrics grouped by tag | Group by user_id and roll up in your database, or a runtime per customer. |
| Customer admins seeing only their own users’ work | Your backend lists conversations list --filter owner_key=user:<id> with an Admin Agent key. |