Skip to main content

Overview

Claude Code limits concurrent sessions per account. To run many agents in parallel (10+), you need to distribute them across multiple Claude subscriptions using profile wrappers.
This guide applies to Claude Code provider only. Other providers (OpenCode, Codex) have different scaling mechanisms.

Rate Limits by Plan

PlanConcurrent SessionsRate Limit
Claude Code Free1~10 requests/min
Claude Code Pro5~50 requests/min
Claude Code MAX10~100 requests/min
A single MAX plan can handle 10 ephemeral workers. For larger teams, distribute agents across multiple MAX or Pro plans.

Architecture

Stoneforge uses profile wrappers to isolate each Claude subscription:
┌─────────────────────────────────────────────┐
│            Stoneforge Director              │
└──────────────┬──────────────────────────────┘

     ┌─────────┴─────────┬──────────────┐
     ▼                   ▼              ▼
┌─────────┐         ┌─────────┐    ┌─────────┐
│ Profile │         │ Profile │    │ Profile │
│  MAX-1  │         │  MAX-2  │    │  PRO-1  │
└────┬────┘         └────┬────┘    └────┬────┘
     │                   │              │
  5 workers          5 workers      3 workers
Each profile wrapper:
  • Uses a separate CLAUDE_CONFIG_DIR for authentication
  • Points to its own Claude subscription
  • Manages its own session pool

Step-by-Step Setup

1

Subscribe to additional Claude plans

Purchase the Claude subscriptions you need:
  • 1 MAX plan = 10 workers
  • 1 Pro plan = 5 workers
For 20 workers, get 2 MAX plans (or 4 Pro plans).
2

Create profile directories

Create separate config directories for each subscription:
mkdir -p ~/.config/claude-profiles/max-1
mkdir -p ~/.config/claude-profiles/max-2
mkdir -p ~/.config/claude-profiles/pro-1
3

Authenticate each profile

Authenticate each profile with its corresponding Claude account:
# MAX plan 1
CLAUDE_CONFIG_DIR=~/.config/claude-profiles/max-1 claude auth login

# MAX plan 2  
CLAUDE_CONFIG_DIR=~/.config/claude-profiles/max-2 claude auth login

# Pro plan 1
CLAUDE_CONFIG_DIR=~/.config/claude-profiles/pro-1 claude auth login
Follow the prompts and sign in with each account.
4

Create wrapper scripts

Create executable wrappers that set CLAUDE_CONFIG_DIR before calling claude:
~/bin/claude-max-1
#!/bin/bash
export CLAUDE_CONFIG_DIR="$HOME/.config/claude-profiles/max-1"
exec claude "$@"
~/bin/claude-max-2
#!/bin/bash
export CLAUDE_CONFIG_DIR="$HOME/.config/claude-profiles/max-2"
exec claude "$@"
~/bin/claude-pro-1
#!/bin/bash
export CLAUDE_CONFIG_DIR="$HOME/.config/claude-profiles/pro-1"
exec claude "$@"
Make them executable:
chmod +x ~/bin/claude-max-1 ~/bin/claude-max-2 ~/bin/claude-pro-1
5

Configure agents with wrappers

When registering agents, specify which wrapper to use:
// Workers 1-10 use MAX plan 1
for (let i = 1; i <= 10; i++) {
  await api.registerWorker({
    name: `e-worker-${i}`,
    workerMode: 'ephemeral',
    createdBy: directorId,
    provider: 'claude',
    executablePath: process.env.HOME + '/bin/claude-max-1',
  });
}

// Workers 11-20 use MAX plan 2
for (let i = 11; i <= 20; i++) {
  await api.registerWorker({
    name: `e-worker-${i}`,
    workerMode: 'ephemeral',
    createdBy: directorId,
    provider: 'claude',
    executablePath: process.env.HOME + '/bin/claude-max-2',
  });
}

// Workers 21-25 use Pro plan
for (let i = 21; i <= 25; i++) {
  await api.registerWorker({
    name: `e-worker-${i}`,
    workerMode: 'ephemeral',
    createdBy: directorId,
    provider: 'claude',
    executablePath: process.env.HOME + '/bin/claude-pro-1',
  });
}

UI Configuration

You can also configure profiles through the Stoneforge dashboard:
1

Open Agent Settings

Navigate to Settings → Agent Defaults in the Stoneforge UI.
2

Set default executable per provider

Configure the default claude wrapper for new agents:
  • Provider: claude
  • Executable Path: /home/user/bin/claude-max-1
3

Override per agent

When creating or editing an agent, you can override the executable:
  • Open the agent edit dialog
  • Set Executable Path to the specific wrapper (e.g., ~/bin/claude-max-2)
Set the most common wrapper as the default, then override for agents that need different profiles.

Balancing Load

Distribute agents evenly across profiles to maximize throughput:

Strategy 1: Round-Robin Assignment

const profiles = [
  { name: 'max-1', path: '~/bin/claude-max-1', capacity: 10 },
  { name: 'max-2', path: '~/bin/claude-max-2', capacity: 10 },
  { name: 'pro-1', path: '~/bin/claude-pro-1', capacity: 5 },
];

let workerIndex = 0;

for (const profile of profiles) {
  for (let i = 0; i < profile.capacity; i++) {
    workerIndex++;
    await api.registerWorker({
      name: `e-worker-${workerIndex}`,
      workerMode: 'ephemeral',
      createdBy: directorId,
      provider: 'claude',
      executablePath: profile.path,
    });
  }
}

Strategy 2: Pool-Based Assignment

Group agents by workload type:
// Frontend workers on MAX-1 (heavy parallel work)
for (let i = 1; i <= 10; i++) {
  await api.registerWorker({
    name: `fe-worker-${i}`,
    workerMode: 'ephemeral',
    createdBy: directorId,
    roleDefinitionRef: frontendRoleDefId,
    provider: 'claude',
    executablePath: '~/bin/claude-max-1',
  });
}

// Backend workers on MAX-2 (heavy parallel work)
for (let i = 1; i <= 10; i++) {
  await api.registerWorker({
    name: `be-worker-${i}`,
    workerMode: 'ephemeral',
    createdBy: directorId,
    roleDefinitionRef: backendRoleDefId,
    provider: 'claude',
    executablePath: '~/bin/claude-max-2',
  });
}

// Stewards on Pro-1 (lower concurrency needs)
await api.registerSteward({
  name: 'm-steward-1',
  stewardFocus: 'merge',
  createdBy: directorId,
  provider: 'claude',
  executablePath: '~/bin/claude-pro-1',
});

Monitoring Profiles

Track session usage per profile to ensure you’re not exceeding limits:
import { createAgentRegistry } from '@stoneforge/smithy';

const registry = createAgentRegistry(api);

// Get all agents grouped by executable
const agents = await registry.listAgents();
const byProfile = new Map<string, number>();

for (const agent of agents) {
  const exec = agent.metadata?.executablePath ?? 'default';
  byProfile.set(exec, (byProfile.get(exec) ?? 0) + 1);
}

// Log current distribution
console.log('Agents per profile:');
for (const [exec, count] of byProfile) {
  console.log(`  ${exec}: ${count} agents`);
}

Cost Optimization

Mix Plan Types

Combine MAX and Pro plans based on workload:
ScenarioRecommended MixCost/Month
Small team (5-10 workers)1 MAX$50
Medium team (15-20 workers)2 MAX$100
Large team (25+ workers)2 MAX + 1 Pro$130
Mixed workload1 MAX + 2 Pro$110

Scale Down During Off-Hours

Adjust agent pools based on activity:
// Peak hours: all workers available
if (isPeakHours()) {
  await enableAllWorkers();
}
// Off-hours: reduce to essential workers
else {
  await enableWorkers(['e-worker-1', 'e-worker-2']); 
  await disableWorkers(nonEssentialWorkerIds);
}

Troubleshooting

Symptom: Agent fails to spawn with auth errorCause: Profile not authenticated or token expiredSolution:
# Re-authenticate the profile
CLAUDE_CONFIG_DIR=~/.config/claude-profiles/max-1 claude auth login

# Verify auth status
CLAUDE_CONFIG_DIR=~/.config/claude-profiles/max-1 claude auth status
Symptom: “Too many concurrent sessions” errorCause: More agents spawned than profile capacitySolution:
  1. Check active sessions for that profile
  2. Reduce maxConcurrentTasks on agents using that profile
  3. Or distribute agents across more profiles
Symptom: “command not found: ~/bin/claude-max-1”Cause: Path not expanded or script not executableSolution:
# Use full path without ~
executablePath: '/home/username/bin/claude-max-1'

# Verify executable permission
ls -l /home/username/bin/claude-max-1
# Should show: -rwxr-xr-x
Symptom: Sessions from one profile appearing in anotherCause: CLAUDE_CONFIG_DIR not set correctly in wrapperSolution: Verify each wrapper sets the env var before calling claude:
#!/bin/bash
export CLAUDE_CONFIG_DIR="$HOME/.config/claude-profiles/max-1"
exec claude "$@"

GitHub Discussion

For detailed examples and community solutions, see:

Claude Code Profile Wrapper Examples

Community-contributed wrapper scripts and profile management strategies

Alternative Providers

If you need to scale beyond Claude Code’s limits, consider:

OpenCode

Self-hosted agents with unlimited concurrency. Requires OpenCode SDK.

Codex

JSON-RPC over stdio. Custom agent implementations.
See the Custom Agents guide for provider-specific configurations.

Custom Agents

Create specialized agent roles

Agent Communication

How agents communicate through channels

Git Worktrees

Understand worktree isolation for parallel work

Build docs developers (and LLMs) love