A simulated software company where AI personas collaborate through a Slack-like chat system. A human operator drops a message into a channel — a feature request, a customer escalation, a pricing question — and an entire organization responds: engineers dig into feasibility, the PM scopes requirements, sales positions the value, finance models the deal, and leadership makes the call. All in real time, all visible in a web UI.
Each agent runs as an autonomous Claude Code instance inside a podman container, interacting with the simulation exclusively through MCP tools. Three processes coordinate the simulation: a Flask web server, an MCP tool server, and a container orchestrator.
Warning: This project runs 10+ concurrent Claude instances per conversation round. A single human message can trigger dozens of API calls across multiple tiers. Token usage adds up fast — monitor your billing closely.
Requirements:
- Python 3.13+
- podman
- Node.js/npm (for building the agent image)
- Google Cloud credentials for Vertex AI
git clone <repo-url>
cd multi-agent-organization
pip install -e .cat > .env <<EOF
CLAUDE_CODE_USE_VERTEX=1
CLOUD_ML_REGION=global
ANTHROPIC_VERTEX_PROJECT_ID=<your-project-id>
EOFYou also need GCP application default credentials:
gcloud auth application-default loginThe agent image contains Claude Code CLI and telemetry hooks. GCP credentials are mounted at runtime.
./scripts/build-agent-image.shThis runs podman build -f container/Dockerfile.agent -t agent-image:latest container/ after verifying prerequisites.
What goes into the image:
- Python 3.13-slim base
- Claude Code CLI (
@anthropic-ai/claude-codevia npm) - Telemetry hooks (
container/agent-hooks.json) for forwarding model/tool events to the MCP server - Runs as non-root
agentuser withsleep infinityas entrypoint
You need three terminals (or use tmux/screen):
Terminal 1 — Flask server:
python main.py server --port 5000 --scenario tech-startupTerminal 2 — MCP server:
python main.py mcp-server --port 5001 --scenario tech-startupTerminal 3 — Container orchestrator:
python main.py chat --model sonnet --scenario tech-startupOpen http://localhost:5000 in your browser. Click New to start a session. The orchestrator will launch one podman container per agent and report ready status.
Type a message in any channel and watch the team respond.
Three processes communicate via HTTP:
Flask Server (port 5000) MCP Server (port 5001)
REST API + SSE + Web UI Per-agent MCP-over-SSE
In-memory state store 32 tools with access control
Session management Audit logging + telemetry
▲ ▲
│ HTTP/REST │ MCP-over-SSE
│ │
▼ │
Container Orchestrator Agent Containers (podman)
Polls for new messages One per persona
Tiered wave execution claude CLI + system prompt
podman exec per turn MCP config mounted
signal_done detection sleep infinity entrypoint
│ ▲
└── podman exec ──────────────────┘
- Flask server holds all simulation state and serves the web UI
- MCP server provides 32 tools (chat, docs, gitlab, tickets, memos, blog, email, meta) that agents use to interact with the simulation
- Orchestrator polls for human messages, launches agent turns via
podman exec claudeinside long-running containers, and manages tiered response ordering
When a human message arrives, agents respond in tiers:
| Tier | Agents | Purpose |
|---|---|---|
| 1 (ICs) | senior, support, sales, devops | Domain experts respond first |
| 2 (Managers) | engmgr, architect, pm, marketing, projmgr | See Tier 1 output, then coordinate |
| 3 (Executives) | ceo, cfo | See everything, make final calls |
Agents within a tier run concurrently (up to --max-concurrent). Tiers run sequentially. Each agent fetches its own context via MCP tools and calls signal_done() when finished.
Each agent turn:
- Orchestrator builds a lightweight turn prompt (~300 bytes) telling the agent which channels have new activity
- Orchestrator runs
podman exec agent-<key> claude -p <prompt> --system-prompt-file /home/agent/system-prompt.md --mcp-config /home/agent/.mcp-config.json ... - Inside the container, Claude Code connects to the MCP server and uses tools:
get_messages()to read context,post_message()to respond,create_ticket()/commit_files()/create_doc()etc. as needed - Agent calls
signal_done()to signal completion - Orchestrator detects the done event and advances to the next tier
If agents post to channels that weren't in the original trigger set, those channels become triggers for a new wave. This continues up to --max-rounds (default 5). After waves complete, autonomous continuation can run up to --max-auto-rounds additional cycles.
| Persona | Role | Tier | Key Channels |
|---|---|---|---|
| Sarah | Product Manager | 2 | #general, #engineering, #sales, #support, #leadership |
| Marcus | Engineering Manager | 2 | #general, #engineering, #support, #devops |
| Priya | Software Architect | 2 | #general, #engineering |
| Alex | Senior Engineer | 1 | #general, #engineering |
| Jordan | Support Engineer | 1 | #general, #engineering, #support, #support-external |
| Taylor | Sales Engineer | 1 | #general, #sales, #sales-external, #marketing |
| Dana | CEO | 3 | #general, #leadership, #sales, #marketing |
| Morgan | CFO | 3 | #general, #leadership, #sales |
| Riley | Marketing | 2 | #general, #marketing, #sales, #sales-external |
| Casey | DevOps Engineer | 1 | #general, #devops, #engineering, #support |
| Nadia | Project Manager | 2 | #general, #engineering, #support, #leadership, #devops |
- Chat — Multi-channel Slack-style messaging with internal and external (customer-facing) channels
- Documents — Folder-based document management with per-persona access control
- GitLab — Mock repository hosting with commits, file browsing, and history
- Tickets — Ticket tracker with priorities, statuses, assignees, comments, and dependency tracking
- Memos — Threaded discussion board for RFCs and proposals
- Blog — Internal and external company blog with comments
- Email — Company-wide broadcast announcements
- Events — Injectable scenario events (production outages, customer escalations, compliance notices)
- Background Tasks — Autonomous worker tasks spawned by agents with full tool access
- NPC Management — Hire/fire agents, modify configs, toggle online/offline from the UI
- Session Management — Save, load, and restore complete simulation state
- Director Channels — Private back-channels for sending instructions to individual agents
python main.py server [--port 5000] [--host 127.0.0.1] [--scenario tech-startup]python main.py mcp-server [--port 5001] [--host 0.0.0.0]
[--flask-url http://127.0.0.1:5000]
[--scenario tech-startup]python main.py chat [--scenario tech-startup]
[--model sonnet|opus|haiku]
[--personas pm,senior,architect]
[--max-rounds 5]
[--max-auto-rounds 0]
[--poll-interval 5.0]
[--server-url http://127.0.0.1:5000]
[--mcp-port 5001]
[--mcp-host auto]
[--container-image agent-image:latest]
[--container-timeout 300]
[--max-turns 50]
[--max-concurrent 4]
[--done-timeout 120]| Option | Default | Description |
|---|---|---|
--model |
sonnet |
Claude model: sonnet, opus, or haiku |
--personas |
all | Comma-separated subset of personas to run |
--max-rounds |
5 | Max ripple waves per response cycle |
--max-auto-rounds |
0 | Max autonomous continuation rounds (0=disabled) |
--max-concurrent |
4 | Max agents running concurrently within a tier |
--container-timeout |
300 | Seconds before killing an agent turn |
--done-timeout |
120 | Seconds to wait for signal_done before advancing tier |
--max-turns |
50 | Max Claude tool-use turns per agent exec |
# Default image name: agent-image:latest
./scripts/build-agent-image.sh
# Custom image name
./scripts/build-agent-image.sh my-agent:v2Prerequisites checked by the script:
podmaninstalledcontainer/agent-hooks.jsonexists
Scenarios define the entire simulation: personas, channels, events, and configuration. Stored under scenarios/<name>/.
| Scenario | Description |
|---|---|
tech-startup |
Default: 11-person engineering org |
dotcom-2000 |
Y2K startup scenario |
dnd-campaign |
Dungeons & Dragons campaign |
company-simulator-team |
Internal team scenario |
research-lab |
Research team scenario |
- Create a directory under
scenarios/with ascenario.yaml - Add character files in
scenarios/<name>/characters/(.CS.mdformat) - Define channels, memberships, response tiers, folders, folder access, and events in the YAML
See scenarios/tech-startup/scenario.yaml for a complete example.
main.py # Entry point (server / mcp-server / chat)
pyproject.toml # Dependencies
container/
Dockerfile.agent # Agent container image
agent-hooks.json # Telemetry hooks for agent containers
scripts/build-agent-image.sh # Image build script
.env # Vertex AI credentials (not committed)
lib/
webapp/ # Flask server, REST API, SSE, web UI
__init__.py # App factory + blueprint registration
state.py # Shared in-memory state management
helpers.py # Initialization + SSE broadcast helpers
template.py # Jinja2 web UI template
routes/ # REST API endpoint blueprints
messages.py # Messaging API + SSE stream
channels.py # Channel management
documents.py # Document CRUD + search
gitlab.py # Repository operations
tickets.py # Ticket management
memos.py # Memo threads
blog.py # Blog posts + replies
emails.py # Email broadcast
npcs.py # Agent management (toggle, hire, fire)
events.py # Event pool + triggers
sessions.py # Session save/load/new
orchestrator.py # Orchestrator status + commands
recaps.py # Recap generation
misc.py # Roles, templates, personas, usage
container_orchestrator.py # Container-based orchestrator + ContainerPool
mcp_server.py # MCP tool server (Starlette + FastMCP)
agent_runner.py # Model utilities, one-shot agent runner
chat_client.py # HTTP client for Flask REST API
personas.py # Persona registry, prompt builders (v2 + v3)
scenario_loader.py # YAML scenario loader
session.py # Session save/load/new
docs.py # Document storage + folder access control
gitlab.py # Mock GitLab (repos, commits, files)
tickets.py # Ticket tracking + ID generation
events.py # Scenario event pool + event log
memos.py # Threaded discussion board
blog.py # Internal + external company blog
email.py # Corporate email system
task_executor.py # Background task execution
cli.py # CLI argument parser
scenarios/
tech-startup/ # Default scenario
scenario.yaml # Channels, tiers, folders, events, settings
characters/ # Per-character prompts (.CS.md files)
var/ # Runtime state (gitignored)
chat.log # Message persistence
docs/ # Document storage
gitlab/ # Repository storage
tickets/ # Ticket storage
logs/ # Agent logs + MCP audit trail
tmp/ # Agent MCP configs + system prompts
instances/ # Saved session snapshots
- claude-agent-sdk — Claude Agent SDK for background tasks and one-shot agents
- flask — Web server and REST API
- mcp — MCP protocol library (FastMCP)
- uvicorn — ASGI server for the MCP server
- httpx — Async HTTP client (MCP → Flask proxy)
- requests — Sync HTTP client (orchestrator → Flask)
- pyyaml — Scenario YAML parsing
- python-dotenv — Environment variable management
- podman — Container runtime (not a Python dependency)
- claude CLI — Claude Code CLI, installed in the agent image via npm