Agents Agents Agent groups

Agent groups

A group manages several agents that do the same job as one unit. You can spread calls across them, let them call each other, keep their tool access and guardrails the same, and share one monthly budget. A group is a grouping over ordinary agents. Each agent keeps its own credential, traces and audit trail.

A group is one saved configuration. Everything except the name and the agents is an optional section, off until you turn it on. Nothing is applied until you click Save, and one Save applies the whole configuration.

Create a group

  1. Open Groups

    Go to Agents and open the Groups tab. Saved groups are listed on the left. Choose New to start a draft.

  2. Name it

    The name must be unique in your workspace. The description is optional.

  3. Add agents

    Pick at least one agent. Each row shows its spend this month once the group is saved.

  4. Turn on the sections you want

    Each section below has its own switch. Leave the rest off.

  5. Click Create group

    Later edits use Save. Anyone with the builder role or higher, or a custom role holding agent_groups:write, can create and edit groups. Viewers can read them. Deleting a group needs an admin.

If a section can't be applied, for example a budget that clashes with another pool, the whole Save fails and nothing changes.

Load balancing

Turn this on to send calls to the group instead of to one agent. Pick a strategy:

StrategyHow the next agent is chosen
Round-robinEach call goes to the next agent in turn. Calls spread evenly.
WeightedYou set a percentage per agent. The percentages must total 100, or the Save is refused. A 70/30 split sends about 70% of calls to the first agent.
FailoverAgents are tried top to bottom. Use the up and down arrows to set the order. The first agent takes every call until it can't.

Calls go through POST /v1/agent-groups/{id}/run. The call takes exactly the same governed path as running one agent directly, so each agent's budget, guardrails, skills and tracing still apply. If load balancing is off, that endpoint returns 409.

When a call moves to the next agent

Every strategy picks an order. If the first agent can't serve the call, Forgebench tries the next one in that order.

The call moves on when:

  • the agent's gateway call fails (502);
  • the agent has used its own budget (402 agent_budget_exceeded), or its model's monthly or daily budget (402 model_budget_exceeded, model_daily_budget_exceeded);
  • the agent's model isn't allowed for the caller (403 model_not_allowed);
  • the agent keeps being refused its tools (429 tool_repeatedly_unauthorized);
  • a budget pool that belongs to that agent alone is used up (402 pool_budget_exceeded or pool_member_share_exceeded);
  • the agent is paused or retired;
  • the agent has failed recently and its breaker is open. A success closes it.

The call is returned to you as is when:

  • a policy refuses it (any other 403 or 400), for example a guardrail block or a missing permission. Another agent would apply the same policy, so retrying only hides the refusal;
  • the budget pool that pays for the call is used up (402 pool_budget_exceeded, pool_member_share_exceeded). That is the group's shared budget when the group has one, and otherwise the caller's own budget pool. Every agent shares it, so another agent would hit the same wall;
  • the workspace budget is exhausted;
  • the request itself is invalid.

If every agent fails, you get the last error. If every agent is paused or tripped, you get 503 no_member_available with the reason for each.

Internal connect

Turn this on to let the agents in the group call each other (agent-to-agent). Forgebench creates a permission for every ordered pair of members, so a group of four gets 12.

Granting a permission is changing what the calling agent may do, so you can only create the pairs whose caller you own (or any, if you're an admin or owner). A pair whose caller you don't own gets no permission at all; an admin saving the group fills it in.

The agent being called must approve too. If you also speak for it (admin, or its owner), the permission is approved at once. If not, it is created as pending until the callee's owner approves it.

Turning it off, or removing an agent from the group, revokes only the permissions the group created. Permissions someone granted by hand are left alone. Saving the group again never undoes a revoke made by an owner or an admin: only a permission the group revoked comes back when you turn the switch on again, and one that had been approved needs a fresh approval unless you can approve for the callee. Each permission granted or revoked leaves its own audit entry, agent.call_binding.granted or agent.call_binding.revoked, marked via: agent_group.

Primary agent

Pick one member as the primary (the star icon on its row). The other agents copy its configuration. Choose what to copy:

  • Inherit MCP access. Each other agent gets the same tool grants as the primary. Tools an agent already had on its own are kept. If the primary loses a tool, the copy is revoked. That includes copies made with Sync all from the primary while inheritance is on. A copy an owner or admin revoked by hand stays revoked.
  • Inherit guardrails. Each other agent takes the primary's guardrail switch, auto-pause settings and per-check policies. This overwrites their own guardrail settings. The review flag (guardrail_review) is not copied: it is runtime state set when an agent is held for review, not configuration.

The primary must be a member. Inheritance needs a primary.

Who can turn it on

Inheritance changes other agents' access, so saving it needs ownership of every other member (or the admin or owner role). If you don't own one, the Save fails with 403 agent_owner_or_admin_required. Inheriting guardrails also needs the guardrails:write permission (or admin), or the Save fails with 403 guardrails_write_required. The same applies to Sync all.

When copies update

The copies re-sync when you save the group, when you add an agent to it, and whenever someone changes the primary's guardrails or tool access, including revoking a whole MCP server or its stale tools. Each re-sync is logged in Recent activity.

A re-sync after an edit is limited to what both people could do by hand: the person who made the edit, and the person who last saved the group with inheritance on (the group remembers them). It writes only to agents that both can change, with guardrails needing guardrails:write from both, and the person who saved it must still be an active member who can change the primary. Agents it skips are not changed, and the edit itself still succeeds. The skipped agents are listed in the sync event in Recent activity. A group saved by a key with no identity never re-syncs after an edit, because there is nobody to check; the copies from the Save itself remain. An approved change plan re-syncs on the saver's authority alone.

What stays when you turn it off

Turning inheritance off, or deleting the group, stops further syncing. It does not remove what was already copied. The matrix labels copied grants as inherited until you remove them.

MCP access

The MCP access table lists every MCP tool any member can use, against each agent. A cell is one of:

  • granted: the agent was given the tool directly;
  • inherited: copied from the primary or by Sync all;
  • missing: the agent can't use it.

Sync all to an agent copies that agent's MCP access to every other member, in one step. It copies MCP tool grants only, not guardrails. Use it to bring the group in line without a primary. It's disabled while you have unsaved changes, so save first. The source agent must be a member.

Shared budget

Optional. Turn on Share a monthly budget, choose whether it's counted in dollars or tokens, then set the monthly limit and optional alert thresholds (percent; the default is 50, 75, 90, 95, 100). A token budget counts prompt and completion tokens, like a token pool. The unit is fixed once the budget exists: to switch, turn the budget off and on again (a Save in the other unit fails with 422 budget_unit_fixed). All the agents' credentials draw on one cap. When it's used up, calls from any of them are stopped.

A run of a member through POST /v1/agents/{id}/run or the group's /run is charged to the group's pool. A call is charged to one pool, because each usage record names the single pool it was charged to and the pool's counters are rebuilt from those records. So for a member run the group's pool takes precedence: it stops the call even when the caller's key sits in a pool of its own, and the caller's own pool is not charged for that run. The usage record names the group's pool and the agent's key that was charged, so the counters rebuild to exactly the live figures. Runs of agents outside a budgeted group are unaffected.

  • Admins only. Builders get 403 admin_required if they try to change the budget. They can still rename the group and change its agents, and the pool follows. Adding or removing an agent changes its spend cap, so a builder must own each agent they add or remove (an admin can add any). Otherwise the Save fails with 403 pool_member_owner_required, listing the agents.
  • An agent with no credential of its own has no share in the pool. Its runs are charged as an ungrouped agent's are, not to another member's share.
  • Behind the scenes this is an agent budget pool. It is named Group: <name>. Changing the limit or the agents updates the pool.
  • An agent whose credential is already in another pool blocks the Save with 409 keys_in_other_pool, and the error names the keys and pools. Remove them from that pool first.
  • Turning the section off archives the pool. The agents go back to their own budgets.

With no shared budget, the group still shows what its agents spent this month. That's information only, and it caps nothing.

Recent activity

The panel under the form lists the latest events, newest first:

  • Served by an agent: each run, with the outcome and how many agents were tried. A run refused by policy shows as refused. A run that no agent could serve shows as failed.
  • MCP sync: a sync from the primary or from Sync all.
  • Config change: a create or update.

Recording an event never blocks a call. If the write fails, the call still completes.

Run a group

curl https://api.forgebench.ai/v1/agent-groups/$GROUP_ID/run \
-H "Authorization: Bearer $FORGEBENCH_KEY" \
-H "Content-Type: application/json" \
-d '{"message": "Summarise this invoice"}'

The request body is the same as for running one agent: message is required, and top_k, dimensions, stream and metadata are optional. The credential needs write access to agents. The response is that agent's usual run response plus three fields:

FieldMeaning
agent_group_idThe group that took the call.
served_by_agent_idThe agent that answered.
attemptsHow many agents were tried. Paused and tripped agents are skipped and not counted.

The usual fields (answer, model, citations, token counts, cost_usd, trace_id) come from the agent that served the call.

A streamed call has no JSON body to hold them. Read these response headers instead: x-agent-group-id, x-served-by-agent-id and x-attempts.

Configuration API

All endpoints are under /v1/agent-groups. They return 404 until Agent Groups is enabled for your deployment.

Method and pathRoleDoes
GET /v1/agent-groupsViewerLists groups with agent count, the member agent ids, strategy and whether they have a budget.
POST /v1/agent-groupsBuilderCreates a group from a full configuration. Returns 201.
GET /v1/agent-groups/{id}ViewerOne group with per-agent spend, the MCP matrix and budget status.
PUT /v1/agent-groups/{id}BuilderReplaces the whole configuration. Sending the same configuration again changes nothing.
DELETE /v1/agent-groups/{id}AdminDeletes the group, revokes the permissions it made and archives its pool. Copied MCP and guardrail settings stay. Returns 204.
GET /v1/agent-groups/{id}/eventsViewerRecent activity. limit is 1 to 200, default 50.
POST /v1/agent-groups/{id}/mcp-syncBuilderBody {"from_agent_id": ...}. Copies that agent's MCP access to the rest.
POST /v1/agent-groups/{id}/runBuilderRuns the group. See above.

A save body has name, description, members (each with agent_id, weight and position), load_balancing (&#123;"strategy": ...&#125; or null), internal_connect, primary_agent_id, inherit (mcp, guardrails) and budget (monthly_limit_usd or monthly_limit_tokens, alert_thresholds, or null). The response's budget has limit_unit and the figures in that unit: monthly_limit_usd, spent_usd, remaining_usd, or monthly_limit_tokens, spent_tokens, remaining_tokens.

Errors

Errors carry a code in detail.

StatusCodeMeaning
409agent_in_other_groupAn agent already belongs to another group. The error lists them.
409group_name_takenAnother group has that name.
409keys_in_other_poolShared budget: an agent's key is already in another pool.
409load_balancing_offYou called /run on a group with load balancing off.
403admin_requiredOnly admins can set or change a shared budget.
403pool_member_owner_requiredA builder added or removed an agent they don't own in a group with a shared budget. Lists the agents.
403agent_owner_or_admin_requiredInheritance or Sync all would change an agent you don't own. Lists the agents.
403guardrails_write_requiredInheriting guardrails needs the guardrails:write permission.
404agent_not_foundA member agent doesn't exist.
422agent_retiredA retired agent can't join.
422duplicate_memberThe same agent is listed twice.
422weights_must_total_100Weighted weights don't add up to 100.
422primary_not_memberThe primary isn't one of the members.
422primary_requiredInheritance is on but there is no primary.
422agent_not_memberfrom_agent_id isn't in the group.
503no_member_availableEvery agent was paused or tripped on a run.

Cookie settings

Our Cookie Policy lists every cookie and what it does.