Configurable Enterprise Simulation Engine
Crucible is a YAML-driven simulation engine for modeling how enterprise teams communicate and operate under pressure. It orchestrates multiple communication channels (Slack, Email, PagerDuty) with LLM-powered agents who have roles, personalities, and organizational context. A built-in pressure engine simulates real-world deadlines and escalation dynamics — GDPR notification windows, insurance reporting requirements, evidence preservation orders — that shape how agents behave as time runs out.
Built on ideas from the OASIS project by CAMEL-AI.org.
-
YAML-driven configuration — define platforms, enterprises, pressures, and org charts entirely in YAML. No code changes needed to create new simulation scenarios.
-
Built-in channel presets — Slack, Email, and PagerDuty ship out of the box. Each channel defines its own actions, observation templates, and database schema. Extend with custom YAML.
-
Pressure engine — countdown timers (GDPR 72-hour window), thresholds (data exfiltration volume), and triggered events (breach confirmed). Pressures escalate through normal → high → critical severity and are injected into agent prompts automatically.
-
Jinja2 prompt templating — agent system prompts and observations are rendered from templates with variables like
{{ role }},{{ personality }}, and{{ pressures }}. Each channel defines its own prompt and observation templates. -
Multi-world orchestration —
CrucibleEnvruns multiple communication channels in parallel with a shared pressure timeline. Agents can operate across Slack and Email simultaneously while pressures tick down globally.
uv pip install git+https://github.com/raxITlabs/crucible.gitClone the repo and install:
git clone https://github.com/raxITlabs/crucible.git
cd crucible
uv pip install -e ".[dev]"Run the built-in cybersecurity incident response scenario:
# quick_start.py
import asyncio
from pathlib import Path
from crucible import (
CrucibleEnv,
ManualAction,
load_enterprise_config,
load_platform_config,
)
BUILTINS = Path("src/crucible/builtins")
async def main():
# Load configs
slack = load_platform_config(str(BUILTINS / "channels/slack.yaml"))
enterprise = load_enterprise_config(str(BUILTINS / "presets/cybersecurity_ir.yaml"))
# Boot the simulation
env = CrucibleEnv(
world_configs=[slack],
pressure_configs=enterprise.pressures,
db_dir="./sim_data",
)
await env.start()
# Round 1: SOC analyst reports the breach
result = await env.step({
"slack": ManualAction(
action_type="send_message",
action_args={
"channel": "#incident-response",
"content": "Breach confirmed. Activating IR playbook.",
},
)
})
print("Round 1:", result)
# Round 2: check pressure state — countdowns have ticked twice
result = await env.step({
"slack": ManualAction(action_type="do_nothing", action_args={})
})
print("\n-- Pressure on incident_commander --")
print(env.get_pressure_text("incident_commander"))
print("\n-- Pressure on soc_analyst --")
print(env.get_pressure_text("soc_analyst"))
await env.stop()
asyncio.run(main())Run it:
uv run python quick_start.pyYou should see the action result and the formatted pressure text showing countdown timers and severity levels for each role.
Crucible uses three types of YAML configuration.
Define a communication platform. Located in src/crucible/builtins/channels/.
platform:
name: slack
display_name: Slack
system_prompt_template: |
You are {{ agent_name }}, a {{ role }} at {{ company }}.
{{ pressures }}
observation_template: |
Channel: #{{ channel_name }}
Recent messages:
{% for msg in messages %}
[{{ msg.timestamp }}] {{ msg.author }}: {{ msg.content }}
{% endfor %}
actions:
- name: send_message
description: Send a message to a Slack channel
parameters:
- name: channel
type: string
- name: content
type: string
category: communication
- name: do_nothing
description: Take no action this round
parameters: []
category: meta
agent_profile_fields:
- name: display_name
type: string
required: true
- name: role
type: string
required: trueBuilt-in channels: Slack (6 actions), Email (4 actions), PagerDuty (5 actions).
Define a simulation scenario with worlds, pressures, and org structure. Located in src/crucible/builtins/presets/.
enterprise:
name: CyberDefend Corp
industry: cybersecurity
size: large
worlds:
- type: channel
name: slack
- type: channel
name: email
pressures:
- name: GDPR 72hr notification
type: countdown
hours: 72
affects_roles: [incident_commander, legal_counsel, privacy_officer]
severity_at_50pct: high
severity_at_25pct: critical
org:
departments: [Security Operations, Incident Response, Legal, Executive]
reporting_lines:
soc_analyst: soc_lead
incident_commander: ciso
ciso: ceo| Type | Trigger | Example |
|---|---|---|
countdown |
Decrements each round based on hours |
GDPR 72-hour notification deadline |
threshold |
Activates when a measured value crosses value/unit |
Data exfiltration exceeds 100 GB |
triggered |
Activates when a named event (triggered_by) fires |
Breach confirmed |
All pressure types support affects_roles (role-based filtering) and severity escalation at 50% and 25% remaining.
CrucibleEnv (orchestrator)
├── PressureEngine (shared across worlds)
│ └── Ticks each round, escalates severity, formats pressure text per role
├── World: slack
│ ├── ConfigurablePlatform (builds action handlers from YAML, persists to SQLite)
│ └── Channel (async message queue between agents and platform)
├── World: email
│ ├── ConfigurablePlatform
│ └── Channel
└── AgentInfo (Jinja2-rendered system prompts with profile + pressure context)
- CrucibleEnv creates one
ConfigurablePlatform+Channelpair per world and a sharedPressureEngine - PressureEngine ticks each simulation round, updating countdowns and escalating severity levels
- ConfigurablePlatform reads action definitions from YAML and dynamically builds handler methods at runtime
- Channel provides async bidirectional message passing between agents and platforms (adapted from OASIS)
- AgentInfo renders Jinja2-templated system prompts using agent profile fields and current pressure state
The flagship preset (cybersecurity_ir.yaml) models a large cybersecurity company responding to a data breach.
Enterprise: CyberDefend Corp
Channels: Slack + Email
Pressures:
- GDPR 72-hour notification countdown (affects incident commander, legal counsel, privacy officer)
- Insurance 48-hour notice countdown (affects incident commander, CFO, legal counsel)
- Evidence preservation triggered event (affects forensic analyst, incident commander, SOC analyst)
- Data exfiltration threshold at 100 GB (affects SOC analyst, forensic analyst, network engineer)
Organization: 5 departments (Security Operations, Incident Response, Legal, Executive, IT Infrastructure) with 10 roles and a full reporting hierarchy from SOC analyst up to CEO.
Crucible is a derivative work that builds on OASIS (Open Agent Social Interaction Simulations) by CAMEL-AI.org.
OASIS is a scalable social media simulator designed to model up to one million agents on platforms like Twitter and Reddit. It introduced the core architecture of LLM agents communicating with platforms through action/observation loops — an architecture that Crucible adapts for enterprise communication scenarios.
-
The
Channelclass for async agent-platform message passing. Crucible'ssrc/crucible/platform/channel.pyis adapted from OASIS with modifications. The original Apache 2.0 attribution header is preserved in the source file. -
The
getattr-based dynamic dispatch pattern used inConfigurablePlatformfor routing actions to handler methods, referenced from OASIS's platform implementation. -
Architectural concepts: the agent-platform-action loop, the separation between a platform (which manages state) and a channel (which manages communication), and the use of SQLite for persistent simulation state.
-
The complete
oasis/directory is retained in this repository for reference and to preserve the original codebase.
OASIS targets social media dynamics at internet scale. Crucible targets enterprise team dynamics under operational pressure. The key additions are:
- YAML-driven configuration replacing code-based setup
- A pressure engine with countdowns, thresholds, and triggered events
- Multi-world orchestration across enterprise communication channels
- Jinja2-templated agent prompts with pressure injection
- Enterprise-specific channels (Slack, Email, PagerDuty) replacing Twitter and Reddit
- Organizational modeling with departments, roles, and reporting lines
@misc{yang2024oasisopenagentsocial,
title={OASIS: Open Agent Social Interaction Simulations with One Million Agents},
author={Ziyi Yang and Zaibin Zhang and Zirui Zheng and Yuxian Jiang and Ziyue Gan and Zhiyu Wang and Zijian Ling and Jinsong Chen and Martz Ma and Bowen Dong and Prateek Gupta and Shuyue Hu and Zhenfei Yin and Guohao Li and Xu Jia and Lijun Wang and Bernard Ghanem and Huchuan Lu and Chaochao Lu and Wanli Ouyang and Yu Qiao and Philip Torr and Jing Shao},
year={2024},
eprint={2411.11581},
archivePrefix={arXiv},
primaryClass={cs.CL},
url={https://arxiv.org/abs/2411.11581},
}OASIS Links: GitHub | Documentation | Paper
We are grateful to the OASIS team at CAMEL-AI.org for creating and open-sourcing their simulation framework. Their work on scalable agent-platform communication provided the foundation for Crucible's communication layer.
Crucible's original code is licensed under AGPL-3.0. See LICENSE for the full text.
Components adapted from OASIS retain their Apache 2.0 license. Attribution headers are preserved in individual source files (see src/crucible/platform/channel.py). The full Apache 2.0 license text is available at licenses/APACHE-2.0.
The complete OASIS codebase in the oasis/ directory remains under its original Apache 2.0 license. Copyright 2023 CAMEL-AI.org.
Crucible contribution guidelines are in development. In the meantime, open an issue or pull request on GitHub.