simpy
Build, inspect, test, and analyze bounded process-based discrete-event simulations with SimPy, including events, resources, interrupts, monitoring, replications, warm-up, and reproducible output analysis.
Works with
---
name: simpy
description: Build, inspect, test, and analyze bounded process-based discrete-event simulations with SimPy, including events, resources, interrupts, monitoring, replications, warm-up, and reproducible output analysis.
license: MIT
---
# SimPy
## Scope
Use this skill for process-based discrete-event models where active entities yield
events and contend for resources: queues, production systems, logistics, networks,
service operations, inventory, and other event-driven systems.
SimPy supplies an event scheduler and modeling primitives. It does **not** choose a
scientifically valid conceptual model, input distribution, warm-up, run length,
replication count, estimand, or causal interpretation. Treat those as simulation-study
methodology, not SimPy API behavior.
## Current release and installation
Verified **2026-07-23**:
- Latest stable: **SimPy 4.1.2**, released on PyPI 2026-05-24; source tag
`4.1.2` points to commit `f4381649`.
- Package metadata requires Python **>=3.8** and classifies CPython 3.8-3.14
plus PyPy. SimPy has no runtime dependencies.
- 4.1.2 adds Python 3.13/3.14 support and modern-interpreter test fixes.
- Upstream and this skill are MIT-licensed.
Create a reproducible environment:
```bash
uv venv --python 3.13
source .venv/bin/activate
uv pip install "simpy==4.1.2"
python -c "import importlib.metadata; print(importlib.metadata.version('simpy'))"
```
Do not silently substitute the `latest` documentation build: it may describe an
unreleased development revision. Use the versioned 4.1.2 links in
`references/sources.md`.
## Model workflow
1. **Define purpose and estimands.** State the decision/question, system boundary,
entities, resources, state, outputs, time units, and terminating event or
steady-state target.
2. **Write a conceptual model first.** Record assumptions, distributions,
routing, priorities, initial conditions, and omitted mechanisms.
3. **Implement generators.** A SimPy process is an event-yielding Python generator.
Register the generator object with `env.process(...)`.
4. **Bound execution.** Give every production run explicit time, entity, event, and
replication caps. Never call `env.run()` on a model containing an endless process.
5. **Separate random streams.** Use local RNG instances for logically distinct
stochastic sources; retain a seed manifest.
6. **Instrument deliberately.** Observe state after the transition of interest,
close time-weighted intervals at the horizon, and test that monitoring does not
alter event order.
7. **Verify and validate.** Test deterministic edge cases, conservation identities,
traces, queue discipline, and analytical benchmarks; compare against system or
expert evidence for the stated purpose.
8. **Run independent replications.** Make intervals from replication-level
estimates, not correlated entities within one run.
9. **Report limitations.** Include initialization, unfinished entities, run length,
seeds/streams, precision, sensitivity, and validation evidence. Never convert
simulation association into a causal claim.
Read `references/simulation-methodology.md` before making inferential claims.
## Minimal bounded model
```python
import random
import simpy
HORIZON = 480.0
arrival_rng = random.Random(101)
service_rng = random.Random(202)
env = simpy.Environment()
server = simpy.Resource(env, capacity=2)
completed = []
def customer(arrival):
with server.request() as request:
yield request
wait = env.now - arrival
yield env.timeout(service_rng.expovariate(1 / 6.0))
completed.append((env.now, wait))
def arrivals():
for _ in range(10_000): # Entity cap.
delay = arrival_rng.expovariate(1 / 4.0)
if env.now + delay >= HORIZON:
return
yield env.timeout(delay)
env.process(customer(env.now))
env.process(arrivals())
env.run(until=HORIZON)
```
The numeric horizon is half-open: normal events scheduled exactly at `480.0` are
not processed. Report unfinished entities rather than silently treating them as
completed observations.
## Core semantics
### Environment and deterministic ordering
`Environment` is single-threaded. The queue is ordered by simulation time, event
priority, then a strictly increasing event ID. Same-time, same-priority events are
therefore processed FIFO in scheduling order. Model processes may represent
concurrency, but callbacks execute sequentially and deterministically.
- `env.now`: unitless simulation clock; choose and document one unit.
- `env.peek()`: next event time or infinity.
- `env.step()`: process one event; raises `EmptySchedule` when empty.
- `env.active_process`: currently executing process, otherwise `None`.
- `env.run()`: drain the queue; unsafe with recurring or endless processes.
`env.run(until=number)` and `env.run(until=event)` are not interchangeable at
boundaries:
- A numeric value schedules an urgent stop event and excludes ordinary events at
that exact time.
- An Event criterion returns that event's value when its stop callback fires.
Other same-time ordering depends on priority and scheduling order.
- In 4.1.2, `Environment.step()` preserves callbacks remaining after
`StopSimulation` by rescheduling the target. Consequently, after
`env.run(until=target)`, `target.processed` can remain `False` until one more
`step()`/`run()` even though its value was returned. Do not use `processed` as the
sole post-run completion test.
See `references/events.md` and `references/monitoring.md`.
### Event, Timeout, Process, and Condition
- An `Event` moves once through not-triggered -> triggered/scheduled -> processed.
`succeed(value)` or `fail(exception)` triggers it once.
- A `Timeout` triggers when created, is scheduled for `now + delay`, and cannot be
manually succeeded again.
- `env.process(generator)` creates a `Process`; the generator resumes with the
yielded event value. Returning from the generator succeeds the Process with that
return value. Uncaught exceptions fail it.
- `AnyOf` / `a | b` and `AllOf` / `a & b` yield a `ConditionValue`: an ordered,
dict-like mapping from **event objects** to their values. Test membership using
the original event objects; do not assume a scalar result.
- `AnyOf` does not cancel losing events. Explicitly cancel pending resource
requests when abandoning them; ordinary timeouts remain scheduled.
### Interrupts
`process.interrupt(cause)` schedules an urgent interruption that throws
`simpy.Interrupt` into the target generator. Catch it around the yielded work that
may be interrupted, inspect `interrupt.cause`, update remaining work, then either
resume, re-yield the original event, or terminate.
Interrupting a process removes its resume callback from its current target; it does
not cancel that target event. A process cannot interrupt itself or a terminated
process. See `references/process-interaction.md`.
## Shared resources
| Type | Semantics |
|---|---|
| `Resource` | FIFO semaphore-like usage slots |
| `PriorityResource` | Queued requests sorted by lower numeric priority first |
| `PreemptiveResource` | Priority queue plus optional preemption of a current user |
| `Container` | Homogeneous numeric level; `put`/`get` wait for capacity/material |
| `Store` | FIFO Python objects |
| `FilterStore` | First available item satisfying the request's predicate |
| `PriorityStore` | Comparable items returned in priority order |
Use a request context manager:
```python
def job(env, resource):
with resource.request() as request:
yield request
yield env.timeout(3)
```
On exit it releases an acquired request or cancels a still-pending one, including
during exception unwinding. For a manually retained pending `put`/`get`/request,
call `cancel()` if an interrupt or timeout makes the process abandon it.
`PreemptiveResource.request(priority=..., preempt=True)` uses lower numbers as
higher priority. The preempted process receives an `Interrupt` whose cause is a
`Preempted` object: `cause.by` is the preempting Process,
`cause.usage_since` is when use began, and `cause.resource` is the resource.
Queued priority takes precedence over the `preempt` flag; mixing preempting and
non-preempting requests needs explicit tests.
Read `references/resources.md` for blocked operations, queue rules, and examples.
## Monitoring and stepping
Prefer explicit domain observations at state transitions. For generic resource
monitoring, wrappers or subclasses can inspect `count`, `queue`, `level`, `items`,
`put_queue`, and `get_queue`. For event tracing, `schedule()` and `step()` are the
central hooks.
Queue measurements are timing-sensitive:
- A request method's pre-state, post-call state, grant callback, and release
callback can all differ at the same simulation timestamp.
- Sample averages weight event observations, not time. Compute area under the
left-continuous state path and divide by elapsed time.
- Add initial and final samples; close the last interval at the analysis horizon.
- `env._queue`, resource `_env`, and monkey-patching are implementation details.
Pin SimPy, isolate the instrumentation, and regression-test after upgrades.
- Tracing every event changes runtime and memory use; cap trace records.
Use `scripts/resource_monitor.py` and `references/monitoring.md`.
## Real-time execution
`simpy.rt.RealtimeEnvironment(initial_time=0, factor=1.0, strict=True)` maps one
simulation unit to `factor` wall-clock seconds. In strict mode, `step()`/`run()`
raises `RuntimeError` when computation falls behind. `strict=False` tolerates lag;
it does not restore timing accuracy. Develop logic with `Environment`, then run
separate timing tests with generous platform-aware tolerances. See
`references/real-time.md`.
## Bundled safe CLIs
All CLIs use a fixed built-in queue model or summarize local artifacts. They reject
unknown JSON keys, URLs, symlinks, non-finite numbers, oversized inputs, and
unbounded time/events/entities/replications. They never evaluate config text,
execute user Python, import plugins, or call a network service.
```bash
# Inspect all options.
python skills/simpy/scripts/bounded_queue_scenario.py --help
python skills/simpy/scripts/replication_runner.py --help
python skills/simpy/scripts/event_trace_summary.py --help
python skills/simpy/scripts/validate_simulation_config.py --help
# Deterministic built-in scenario.
python skills/simpy/scripts/bounded_queue_scenario.py
# Independent replications with replication-level Student-t intervals.
python skills/simpy/scripts/replication_runner.py
# Validate only; no simulation runs.
python skills/simpy/scripts/validate_simulation_config.py config.json
```
The replication runner refuses one-replication intervals. Its intervals quantify
Monte Carlo uncertainty under the configured model; they neither validate the model
nor identify causal effects. See `references/cli-guide.md`.
## Testing
Use deterministic unit tests for ordering, boundary times, conditions, interrupts,
all resource disciplines, conservation, event/entity limits, seed reproducibility,
and monitor non-interference. Add stochastic tests only as broad distributional
checks with fixed seeds; avoid brittle exact sample estimates.
Run the skill's suite in the exact pinned environment without bytecode artifacts:
```bash
PYTHONDONTWRITEBYTECODE=1 uv run --isolated --no-project \
--python 3.13 --with "simpy==4.1.2" \
python -m unittest discover -s tests/simpy -v
```
## References
- `references/events.md` — scheduler, lifecycle, run boundaries, conditions
- `references/process-interaction.md` — generators, shared events, interrupts
- `references/resources.md` — all Resource, Container, and Store variants
- `references/monitoring.md` — time weighting, queue timing, tracing, stepping
- `references/real-time.md` — factor, strict mode, drift, timing tests
- `references/simulation-methodology.md` — replications, warm-up, validation, CI
- `references/cli-guide.md` — schemas, bounds, outputs, and safe CLI examples
- `references/sources.md` — dated official and primary-method sourcesMore Observability skills
google-agents-cli-observability
google/agents-cli
>
azure-observability
microsoft/azure-skills
Azure Observability Services including Azure Monitor, Application Insights, Log Analytics, Alerts, and Workbooks. Provides metrics, APM, distributed tracing, KQL queries, and interactive reports. USE FOR: Azure Monitor, Application Insights, Log Analytics, Alerts, Workbooks, metrics, APM, distributed tracing, KQL queries, interactive reports, observability, monitoring dashboards. DO NOT USE FOR: instrumenting apps with App Insights SDK (use appinsights-instrumentation), querying Kusto/ADX clusters (use azure-kusto), cost analysis (use azure-cost-optimization).
workers-best-practices
cloudflare/skills
Reviews and authors Cloudflare Workers code against production best practices. Load when writing new Workers, reviewing Worker code, configuring wrangler.jsonc, or checking for common Workers anti-patterns (streaming, floating promises, global state, secrets, bindings, observability). Biases towards retrieval from Cloudflare docs over pre-trained knowledge.

