alterlab-pufferlib — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited alterlab-pufferlib (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
PufferLib is a high-performance reinforcement learning library designed for fast parallel environment simulation and training. It achieves training at millions of steps per second through optimized vectorization, native multi-agent support, and efficient PPO implementation (PuffeRL). The library provides the Ocean suite of 20+ environments and seamless integration with Gymnasium, PettingZoo, and specialized RL frameworks.
Use this skill when:
PuffeRL is PufferLib's optimized PPO trainer (CleanRL-derived, with optional LSTM via models.LSTMWrapper) built for high-throughput training.
Recommended path — CLI / high-level helper. Drive training from a config (an .ini in pufferlib/config/) rather than hand-wiring the trainer:
# CLI: env name resolves to a registered config + Ocean env
puffer train puffer_breakout --train.device cuda --train.learning-rate 0.015import pufferlib.pufferl as pufferl
# train(env_name, args=None, vecenv=None, policy=None, logger=None)
pufferl.train('puffer_breakout')Manual loop. PuffeRL(config, vecenv, policy, logger=None) — note the first arg is a config dict (not flat kwargs), the env arg is vecenv, and the loop is driven by global_step. The three loop methods are real: evaluate(), train(), mean_and_log().
import pufferlib.vector
from pufferlib.pufferl import PuffeRL, load_config
# Native PufferEnv -> default backend=PufferEnv. For wrapped (Gymnasium/
# PettingZoo) envs you MUST pass backend=pufferlib.vector.Multiprocessing.
vecenv = pufferlib.vector.make(MyPufferEnv, num_envs=256)
# load_config returns a nested args dict (sections: 'train', 'vec', 'env', ...)
# with defaults from pufferlib/config/*.ini. PuffeRL takes the 'train' section.
args = load_config('puffer_breakout')
config = {**args['train'], 'env': 'puffer_breakout'}
config['device'] = 'cuda'
trainer = PuffeRL(config, vecenv, my_policy)
while trainer.global_step < config['total_timesteps']:
trainer.evaluate() # Collect rollouts
trainer.train() # Train on batch
trainer.mean_and_log() # Aggregate + logFor comprehensive training guidance, read references/training.md for:
Create custom high-performance environments with the PufferEnv API.
Basic environment structure:
import numpy as np
import gymnasium
from pufferlib import PufferEnv
class MyEnvironment(PufferEnv):
def __init__(self, buf=None):
# Define spaces BEFORE calling super().__init__(buf)
self.single_observation_space = gymnasium.spaces.Box(
low=-np.inf, high=np.inf, shape=(4,), dtype=np.float32)
self.single_action_space = gymnasium.spaces.Discrete(4)
self.num_agents = 1
super().__init__(buf)
def reset(self, seed=None):
# Reset state and return (observation, info-list)
obs = self._get_observation()
return obs, []
def step(self, action):
# Execute action, compute reward, check termination/truncation
obs = self._get_observation()
rewards = self._compute_reward()
terminals = self._is_done()
truncations = self._is_truncated()
info = []
return obs, rewards, terminals, truncations, infoUse the template script: scripts/env_template.py provides complete single-agent and multi-agent environment templates with examples of:
For complete environment development, read references/environments.md for:
Achieve maximum throughput with optimized parallel simulation.
Vectorization setup:
import pufferlib.vector
# Pass an env-constructor callable. Default backend=PufferEnv is native-only;
# for wrapped (Gymnasium/PettingZoo) envs add backend=pufferlib.vector.Multiprocessing.
env = pufferlib.vector.make(env_creator, num_envs=256, num_workers=8)
# Performance benchmarks (PufferLib's published figures; vary by env/hardware):
# - Pure Python envs: 100k-500k SPS
# - C-based envs: 100M+ SPS
# - With training: 400k-4M total SPSKey optimizations:
For vectorization optimization, read references/vectorization.md for:
Build policies as standard PyTorch modules with optional utilities.
Basic policy structure:
import torch.nn as nn
from pufferlib.pytorch import layer_init
class Policy(nn.Module):
def __init__(self, observation_space, action_space):
super().__init__()
# Encoder
self.encoder = nn.Sequential(
layer_init(nn.Linear(obs_dim, 256)),
nn.ReLU(),
layer_init(nn.Linear(256, 256)),
nn.ReLU()
)
# Actor and critic heads
self.actor = layer_init(nn.Linear(256, num_actions), std=0.01)
self.critic = layer_init(nn.Linear(256, 1), std=1.0)
def forward(self, observations):
features = self.encoder(observations)
return self.actor(features), self.critic(features)For complete policy development, read references/policies.md for:
Seamlessly integrate environments from popular RL frameworks.
Gymnasium integration:
import gymnasium as gym
import pufferlib.emulation
import pufferlib.vector
# Wrap a Gymnasium env in a GymnasiumPufferEnv, then vectorize.
# Wrapped (non-native) envs require an explicit backend (Serial or Multiprocessing);
# the default backend=PufferEnv is only for native PufferEnvs.
def env_creator():
return pufferlib.emulation.GymnasiumPufferEnv(
env_creator=lambda: gym.make('CartPole-v1'))
env = pufferlib.vector.make(
env_creator, num_envs=256, backend=pufferlib.vector.Multiprocessing)PettingZoo multi-agent:
import pufferlib.emulation
import pufferlib.vector
from pettingzoo.butterfly import knights_archers_zombies_v10
# Wrap a PettingZoo env in a PettingZooPufferEnv, then vectorize.
def env_creator():
return pufferlib.emulation.PettingZooPufferEnv(
env_creator=lambda: knights_archers_zombies_v10.parallel_env())
env = pufferlib.vector.make(
env_creator, num_envs=128, backend=pufferlib.vector.Multiprocessing)Supported frameworks:
For integration details, read references/integration.md for:
scripts/train_template.py as starting pointreferences/training.md for optimizationscripts/env_template.pyreset() and step() methodspufferlib.emulation.GymnasiumPufferEnv and vectorize with pufferlib.vector.make()references/environments.md for advanced patternsreferences/vectorization.md if neededlayer_init for proper weight initializationreferences/policies.mdreferences/vectorization.md for systematic optimizationtrain_template.py - Complete training script template with:
env_template.py - Environment implementation templates:
training.md - Comprehensive training guide:
environments.md - Environment development guide:
vectorization.md - Vectorization optimization:
policies.md - Policy architecture guide:
integration.md - Framework integration guide:
scripts/train_template.py and scripts/env_template.py provide solid starting pointslayer_init from pufferlib.pytorch for policiesimport pufferlib.vector
# Atari (pass an env-constructor callable)
env = pufferlib.vector.make(make_pong_env, num_envs=256)
# Procgen
env = pufferlib.vector.make(make_coinrun_env, num_envs=256)
# Minigrid
env = pufferlib.vector.make(make_minigrid_env, num_envs=256)import pufferlib.vector
# PettingZoo, wrapped via PettingZooPufferEnv (needs an explicit backend)
env = pufferlib.vector.make(
make_pistonball_env, num_envs=128, backend=pufferlib.vector.Multiprocessing)
# One shared policy serves all agents (single_observation_space / single_action_space
# are per-agent). Pass config (dict), vecenv, policy positionally to PuffeRL.
policy = create_policy(env.single_observation_space, env.single_action_space)
trainer = PuffeRL(config, env, policy)import pufferlib.vector
# Create custom environment (a native PufferEnv subclass)
class MyTask(PufferEnv):
# ... implement environment ...
# Native PufferEnv -> default backend=PufferEnv is fine here.
env = pufferlib.vector.make(MyTask, num_envs=256)
trainer = PuffeRL(config, env, my_policy) # config is a dict (see Training above)import pufferlib.vector
# Maximize throughput (pass an env-constructor callable)
env = pufferlib.vector.make(
my_env_creator, # env constructor callable
num_envs=1024, # Large batch
num_workers=16, # Many workers
backend=pufferlib.vector.Multiprocessing,
)# Pin the 3.0 line — the config-dict trainer API and import paths in this skill
# target it. The dev 4.0 branch differs.
uv pip install "pufferlib==3.0.*"~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.