Skip to content
Guides · Agent cookbook

How Do I Give Each Team's Agent Its Own Tools From One Agent?

Updated October 27, 2026 .md

Short answer: Keep one agent and give each team a sandbox template. Save a versioned named snapshot per team with its CLI tools, MCP servers and instructions, label it with the team name, and have the agent create with fromLabels. Pin a release label to test a new version before the agent switches to it.

The agent's code stays the same for every team. What changes is the machine it works in. A web team's sandbox has a linter and a filesystem MCP server; a data team's has csvkit and a SQLite MCP server. The agent only needs to know which team asked, and it turns that into labels.

This page covers the per-team part: labels, versions, switching and rollback. For how named snapshots work, see Turn a sandbox into a reusable template. For caching slow dependency installs, see Cache dependencies in a named snapshot.

What goes where#

Sandboxer has two things that could hold "a team's setup". They hold different things.

Put it in What it holds Pick it at create with
A named snapshot per team The whole disk: CLI tools, MCP servers, .mcp.json, AGENTS.md, editor and linter config fromLabels (or from)
A named environment per team Variables, secret files, GitHub repos and credential switches (Environments) environment (--environment on the CLI)
Labels on each sandbox Who it belongs to, so you can list and count a team's sandboxes labels

An environment can't install a tool. It writes variables and files and clones repos. So the tools go in the snapshot, and a team's secrets go in an environment. Keep secrets out of templates. We didn't test per-team environments for this page; everything else below ran on prod.

Results#

We ran this on prod on 2026-10-27 between 15:47 and 15:52 UTC with small sandboxes (2 vCPU, 4 GB). Times are single runs, wall clock from the create call to state: ready, polled every 0.25 s.

Step Time
Fresh sandbox, no template 1.95 s
From the web team template (fromLabels team=web, release=1) 1.95 s
From the data team template (fromLabels team=data, newest) 1.94 s
Install the web team's tools in a fresh sandbox 5.4 s
Install the data team's tools with uv tool install 0.8 s
Save a versioned team template 1.3 to 1.4 s

In this run, starting from a template took the same time as starting fresh. Since the warm pool shipped on 2026-10-27, Backend measured fresh small and default creates from the standard image at a median of 0.69 s (90% within 1.15 s, from US-East); creates from a snapshot boot as before, so a fresh start can now be faster than a template start. Our toolsets were small, so the install time a template saves here is a few seconds. The bigger win is that every sandbox for a team has the same tools, versions and config, and that you change them in one place.

Step 1: build and save each team's template#

Each team gets a short script. This is the web team's:

#!/bin/bash
# Team "web": its CLI tools, its MCP server and its agent instructions.
set -euo pipefail
cd /home/user
sudo npm install -g --silent @biomejs/biome@2 @modelcontextprotocol/server-filesystem
cat > .mcp.json <<'J'
{ "mcpServers": { "files": { "command": "mcp-server-filesystem", "args": ["/home/user"] } } }
J
printf '# Team: web\nFormat and lint with biome before every commit.\n' > AGENTS.md
printf 'team=web\nrelease=1\n' > .team

Global npm installs need sudo in a sandbox; without it the install fails with a permissions error. The data team's script runs uv tool install -q csvkit and uv tool install -q mcp-server-sqlite, and points its .mcp.json at /home/user/data.db. The .mcp.json format is the project-scoped MCP file that Claude Code reads; use whatever file your agent reads.

Run the script in a sandbox, then save it as a versioned named snapshot with labels. Labels are set through the API; the CLI has no labels flag yet (API labels).

curl -sS -X POST https://sandboxer.com/api/v1/named-snapshots \
  -H "Authorization: Bearer $SANDBOXER_API_KEY" -H "Content-Type: application/json" \
  -d '{"sandboxId":"sb_xx6707mzdx","name":"teamtpl-web","versioned":true,"ifLatest":0,"keep":2,
       "labels":{"tpl":"teamtpl","team":"web","release":"1"}}'
teamtpl-web-v1 ready in 1.4 s: {"series":"teamtpl-web","version":1,"labels":{"release":"1","team":"web","tpl":"teamtpl"}}

What the fields do:

  • versioned: true saves teamtpl-web-v1, then -v2 and so on, instead of replacing the template in place.
  • ifLatest saves only if the newest version is still that number. Two people updating the same team's template at once can't overwrite each other. A second save with ifLatest: 0 got 409 version_conflict with "details":{"latest":1}.
  • keep: 2 deletes the oldest versions once the new one is ready, so you always have the current one and one to roll back to.
  • release repeats the version number as a label so the agent can pin it. The tpl label keeps your templates apart from any other snapshots on the account.

To save test sandboxes, we built both teams' templates in one builder: we saved the web template, removed its tools, then installed the data team's. In practice, use a fresh builder per team.

Step 2: the agent picks a template by label#

The agent keeps one small table: team name to labels. When a request comes in, it creates the sandbox with fromLabels and tags it with the team:

curl -sS -X POST https://sandboxer.com/api/v1/sandboxes \
  -H "Authorization: Bearer $SANDBOXER_API_KEY" -H "Content-Type: application/json" \
  -d '{"type":"small","name":"teamtpl-2","ttlSeconds":1800,
       "fromLabels":{"tpl":"teamtpl","team":"web","release":"1"},
       "labels":{"tpl":"teamtpl","team":"web"}}'

fromLabels starts from the newest ready named snapshot that carries all of the labels. Two ways to use it:

Agent sends Gets Use it when
{"team":"data"} (plus your tpl label) The newest ready version, as soon as it's saved The team wants updates right away
{"team":"data","release":"2"} Exactly that version You want to test a new version before the agent switches

If nothing matches, no sandbox is created. Asking for a release that doesn't exist returned:

{"ok":false,"error":{"code":"snapshot_not_found","status":404,"message":"No ready named snapshot has all of those labels."}}

The labels on the sandbox itself are separate from fromLabels. They let you list one team's sandboxes with GET /sandboxes?labels=tpl=teamtpl,team=web, which returned just sb_o10ziqe58r ready.

Step 3: check what each team's agent sees#

We ran the same check in a sandbox from each template. It prints the team file, which tools are on the PATH, and the MCP servers in .mcp.json:

== team=web release=1
biome: yes
mcp-server-filesystem: yes
csvsql: no
mcp-server-sqlite: no
sqlite-utils: no
mcp: ["files"]
== team=data release=2
biome: no
mcp-server-filesystem: no
csvsql: yes
mcp-server-sqlite: yes
sqlite-utils: yes
mcp: ["sqlite"]

Each team gets its own tools and none of the other team's. To check that an MCP server really starts, send it initialize and tools/list over stdio. The web template's filesystem server answered with its 14 tools: read_file, read_text_file, … list_allowed_directories.

Step 4: update a template safely#

Never edit what the agent is using. Make a new version, test it, then switch.

  1. Start a sandbox from the current version and make the change. We added uv tool install -q sqlite-utils and set release=2.
  2. Save with "versioned":true,"ifLatest":1,"keep":2 and the labels team=data, release=2. It saved as teamtpl-data-v2 in 1.3 s.
  3. Start a sandbox with fromLabels release=2 and run your smoke test. Start each MCP server; don't just check that the binary exists.
  4. If it passes, change the team's row in the agent's table to release=2. If something goes wrong later, set it back to the previous release: keep: 2 still has it.

Our smoke test caught a real break. The SQLite MCP server installed fine, and command -v found it, but it crashed on start:

  File ".../mcp_server_sqlite/server.py", line 173, in main
    @server.list_resources()
     ^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Server' object has no attribute 'list_resources'

uv tool install had pulled the newest mcp library (2.3.0), which that server version doesn't support. Pinning the library fixed it:

uv tool install -q --force mcp-server-sqlite --with "mcp<2"
read_query, write_query, create_table, list_tables, describe_table, append_insight

We saved that as teamtpl-data-v3 with ifLatest: 2. Because of keep: 2, v1 was deleted, and v2 and v3 remained. The lesson for team templates: pin tool and library versions in the build script, and smoke-test each MCP server before you switch. Unpinned installs can change between two builds of the same script.

Saving a new version doesn't touch running sandboxes. A template is copied at create, so only sandboxes created after the switch get it.

What it costs#

Templates have no separate charge. What they store counts toward your plan's included storage, along with stopped sandboxes: 10 GB on the free trial (Billing). With keep: 2, each team holds at most two versions. GET /named-snapshots shows each one's storedBytes once it has been measured; ours hadn't been measured before we deleted them.

The sandboxes cost what any sandbox costs: a small sandbox is $0.018/hour, billed per second, so a 10-minute agent task on one costs $0.003. Building a template means one builder sandbox for a few minutes. Delete the builder after the save; the template doesn't depend on it.

FAQ#

Do I need a separate agent or API key per team?#

No. One agent with one key can create from any team's template; the team only decides which labels it sends. Give each team its own named environment if their secrets differ.

Should I use from with a name or fromLabels?#

Either works. from takes an exact name such as teamtpl-data-v2, or a series name for its newest ready version. fromLabels lets the agent describe what it wants (team, release) without knowing names, and you can add more labels later, such as os or size.

What happens to a team's running sandboxes when I save a new version?#

Nothing. They keep the disk they started with. Only new sandboxes get the new version, and only once the agent asks for it.

Can I put a team's API keys in its template?#

Don't. Anyone who starts a sandbox from the template gets the file. Put secrets in a named environment per team, which keeps them versioned and separate from the tools.

What if two teams need almost the same tools?#

Build both from one base script and add each team's extras on top, then save each as its own series. Each series keeps its own versions and labels, so updating one team never changes the other.

More guides

Top AI sandbox platforms for code execution in 2026, ranked

For running AI-written code we rank Sandboxer, Freestyle and E2B first: each gives code its own VM with an API or SDK and can pause with memory. Pick Daytona for Windows or GPUs, Modal or Northflank for GPUs at scale, E2B or Northflank to run in your own cloud, and Vercel Sandbox if your app lives on Vercel.

Read the guide
Best sandboxes for running coding agents (Claude Code, Codex, Gemini CLI) in 2026, ranked

For coding agents we rank Sandboxer first: a full Ubuntu VM with Claude Code and Codex preinstalled, Docker, and stop-and-resume that keeps the agent's session in memory. Freestyle and Amp Orbs also keep memory across pauses. Pick E2B for prebuilt agent templates on open source, Docker Sandboxes for free local runs, and Codespaces if you live in GitHub.

Read the guide
Best Daytona sandbox alternatives in 2026, ranked

The best Daytona alternatives depend on why you're switching. For a full Linux microVM on every sandbox with memory-saving stop and Docker, we rank Sandboxer first. E2B suits open source and self-hosting, Modal massive short-job fleets, Northflank bring-your-own-cloud with GPUs, and Vercel Sandbox apps on Vercel.

Read the guide
Best E2B alternatives in 2026, ranked

If you're leaving E2B for longer sessions or a fuller machine, we rank Sandboxer first, then Freestyle: both give each sandbox a full Linux VM that keeps memory across pauses, with Docker and no short session cap. Pick Daytona for Windows or GPUs, Northflank for bring-your-own-cloud, and stay on E2B if you need open source.

Read the guide