OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      ab16f19ff4fd
DATE      2025-07-20
SUBJECT   nix: refactor apps
FILES     12 CHANGED
HASH      ab16f19ff4fd
DATE      2025-07-20
SUBJECT   nix: refactor apps
FILES     12 CHANGED
 

diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..5a2a5e5
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,179 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with cod
e in this repository.
+
+## Project Overview
+
+This is a Nix-based data pipeline for generating World of Warcraft simulation lea
derboards and statistics. The project uses the wowsims CLI engine to create a theo
rycrafting website similar to bloodmallet, showing spec performance rankings and t
rinket data for WoW Mists of Pandaria.
+
+### Project Vision
+- Generate spec simulation leaderboards across different encounter types
+- Provide trinket performance data and rankings
+- Serve results via static website with JSON data files
+- Automate updates via GitHub Actions when upstream wowsims changes
+- Use Nix for reproducible builds and server configuration
+
+## Development Environment
+
+### Setup
+- Use `nix develop` to enter the development shell which provides `wowsimcli`
+- The project uses a Nix flake with inputs from the wowsims MoP fork
+
+### Key Commands
+- `nix develop` - Enter development environment with wowsimcli available
+- `wowsimcli sim --infile input.json` - Run simulation with input file
+- `wowsimcli sim --infile input.json --outfile results.json` - Save results to fi
le
+- `nix flake show` - Show available flake outputs
+- `nix build` - Build packages (future: website and data generation)
+
+## Architecture
+
+### Core Structure
+- `nix/lib/` - Core simulation library functions
+- `nix/lib/default.nix` - Main library exports (target, encounter, player, raid)
+- `nix/lib/extend.nix` - Extends nixpkgs lib with sim functions
+- `docs/` - Example JSON configurations for CLI input
+
+### Key Components
+
+#### Player Configuration (`nix/lib/player.nix`)
+- `mkPlayer` function creates player configurations from:
+  - Race, class, spec selection
+  - Gearsets loaded from wowsims JSON files
+  - APL (Action Priority List) rotations
+  - Consumables, talents, glyphs, professions
+  - Challenge mode support
+
+#### Target/Encounter System (`nix/lib/target.nix`)
+- Predefined target types: `defaultRaidBoss`, `smallTrash`, `largeTrash`
+- Configurable mob stats, damage, and mechanics
+
+#### Simulation (`nix/lib/simulation.nix`)
+- `mkSim` function creates full simulation configurations
+- Supports iterations, random seeds, different sim types
+
+### Data Sources
+- Gearsets: `${wowsims}/ui/${class}/${spec}/gear_sets/${gearset}.gear.json`
+- APLs: `${wowsims}/ui/${class}/${spec}/apls/${apl}.apl.json`
+- References external wowsims repository for game data
+
+## File Organization
+- Configuration examples in `docs/example_cli_input_windwalker.json`
+- Nix library functions organized by domain (player, target, encounter, simulatio
n)
+- No traditional package.json or test files - this is a pure Nix project
+
+## Input JSON Schema
+
+The wowsimcli expects complex JSON input files with this hierarchy:
+
+### Top-Level Structure
+```json
+{
+  "requestId": "string",
+  "type": "SimTypeIndividual", 
+  "raid": RaidConfig,
+  "encounter": EncounterConfig,
+  "simOptions": SimulationOptions
+}
+```
+
+### Key Schema Components
+- **Raid**: Contains 5 parties (25-person raid), each with 5 player slots, plus r
aid-wide buffs/debuffs
+- **Player**: Complex nested structure with equipment (16 slots), consumables, ta
lents, spec-specific options, and APL rotations
+- **Equipment**: Items with IDs, gems, enchants, reforging, tinkers
+- **APL (Action Priority Lists)**: Deep conditional logic trees for spell rotatio
n decisions
+- **Encounter**: Target configuration, fight duration, execute phases, enemy stat
s
+- **Enumeration Patterns**: Prefixed types like "RaceBloodElf", "ClassMonk", "Mob
TypeMechanical"
+
+### Critical Details
+- Equipment items use game database IDs for items/gems/enchants
+- APL system uses complex nested conditions (and/or/cmp operators)
+- Stats arrays are fixed-length (22 elements for target stats)
+- Empty `{}` objects serve as placeholders for unused slots
+- Spec-specific config uses dynamic keys like `"windwalkerMonk": {...}`
+
+## Data Pipeline
+
+### Planned Workflow
+1. **Input Generation**: Nix functions create JSON input files matching wowsims s
chema
+2. **Simulation**: wowsimcli processes inputs and generates result data
+3. **Aggregation**: Results are collected into static JSON files for website cons
umption
+4. **Website**: Static site serves leaderboards and trinket data
+5. **Automation**: GitHub Actions trigger updates when upstream wowsims changes
+
+### Target Simulations
+- **Encounter Types**: Single Target, Multi-Target, Short Single Target
+- **Scope**: All specs initially, trinket comparisons later
+- **Output**: JSON files for web frontend consumption
+
+## Composable Component Design
+
+### Class Component Pattern
+The project uses a layered composition approach for building reusable class confi
gurations:
+
+```nix
+{
+  lib,
+  components,
+  ...
+}: let
+  inherit (lib.sim.player) mkPlayer;
+  inherit (components.consumables) agilityDps;
+
+  # Spec-specific builder function
+  mkWindwalker = {
+    race,
+    apl,
+    gearset, 
+    talents,
+  }: mkPlayer {
+    class = "monk";
+    spec = "windwalker";
+    inherit race gearset talents apl;
+    consumables = agilityDps;  # Shared consumable set
+  };
+
+  # Organized configurations by tier and scenario
+  windwalker = {
+    talents = {
+      xuen = "213322";  # Single target build
+      rjw = "233321";   # AoE build
+    };
+    p1 = {
+      singleTarget = mkWindwalker {
+        race = "orc";
+        apl = "default";
+        gearset = "dw_p1_bis";
+        talents = windwalker.talents.xuen;
+      };
+      aoeOrc = mkWindwalker {
+        race = "orc";
+        apl = "default"; 
+        gearset = "dw_p1_bis";
+        talents = windwalker.talents.rjw;
+      };
+    };
+  };
+in windwalker
+```
+
+### Design Benefits
+- **Shared Defaults**: Common consumables, base configurations
+- **Scenario Organization**: Grouped by content tier (p1, p2) and encounter type
+- **Talent Variants**: Named talent configurations for different playstyles
+- **Race Flexibility**: Easy to create variants for different races
+- **Inheritance Chain**: `mkWindwalker` ? `mkPlayer` ? JSON output
+
+## Working with the Code
+- Build reusable Nix components following the layered composition pattern
+- Create spec builders that inherit from `mkPlayer` with sensible defaults
+- Organize configurations by content tier and encounter scenario
+- Keep individual functions small and focused for maintainability
+- Test changes by entering `nix develop` and running `wowsimcli` with generated c
onfigs
+- All simulation data comes from the referenced wowsims fork
+- Challenge mode can be enabled on equipment for different stat scaling
+
+## Future Development
+- GitHub Actions integration for automated simulation updates
+- Website packaging and server configuration via Nix
+- Trinket simulation expansion beyond basic spec rankings
\ No newline at end of file

diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..5a2a5e5
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,179 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code 
(claude.ai/code) when working with code in t
his repository.
+
+## Project Overview
+
+This is a Nix-based data pipeline for gener
ating World of Warcraft simulation leaderboa
rds and statistics. The project uses the wow
sims CLI engine to create a theorycrafting w
ebsite similar to bloodmallet, showing spec 
performance rankings and trinket data for Wo
W Mists of Pandaria.
+
+### Project Vision
+- Generate spec simulation leaderboards acr
oss different encounter types
+- Provide trinket performance data and rank
ings
+- Serve results via static website with JSO
N data files
+- Automate updates via GitHub Actions when 
upstream wowsims changes
+- Use Nix for reproducible builds and serve
r configuration
+
+## Development Environment
+
+### Setup
+- Use `nix develop` to enter the developmen
t shell which provides `wowsimcli`
+- The project uses a Nix flake with inputs 
from the wowsims MoP fork
+
+### Key Commands
+- `nix develop` - Enter development environ
ment with wowsimcli available
+- `wowsimcli sim --infile input.json` - Run
 simulation with input file
+- `wowsimcli sim --infile input.json --outf
ile results.json` - Save results to file
+- `nix flake show` - Show available flake o
utputs
+- `nix build` - Build packages (future: web
site and data generation)
+
+## Architecture
+
+### Core Structure
+- `nix/lib/` - Core simulation library func
tions
+- `nix/lib/default.nix` - Main library expo
rts (target, encounter, player, raid)
+- `nix/lib/extend.nix` - Extends nixpkgs li
b with sim functions
+- `docs/` - Example JSON configurations for
 CLI input
+
+### Key Components
+
+#### Player Configuration (`nix/lib/player.
nix`)
+- `mkPlayer` function creates player config
urations from:
+  - Race, class, spec selection
+  - Gearsets loaded from wowsims JSON files
+  - APL (Action Priority List) rotations
+  - Consumables, talents, glyphs, professio
ns
+  - Challenge mode support
+
+#### Target/Encounter System (`nix/lib/targ
et.nix`)
+- Predefined target types: `defaultRaidBoss
`, `smallTrash`, `largeTrash`
+- Configurable mob stats, damage, and mecha
nics
+
+#### Simulation (`nix/lib/simulation.nix`)
+- `mkSim` function creates full simulation 
configurations
+- Supports iterations, random seeds, differ
ent sim types
+
+### Data Sources
+- Gearsets: `${wowsims}/ui/${class}/${spec}
/gear_sets/${gearset}.gear.json`
+- APLs: `${wowsims}/ui/${class}/${spec}/apl
s/${apl}.apl.json`
+- References external wowsims repository fo
r game data
+
+## File Organization
+- Configuration examples in `docs/example_c
li_input_windwalker.json`
+- Nix library functions organized by domain
 (player, target, encounter, simulation)
+- No traditional package.json or test files
 - this is a pure Nix project
+
+## Input JSON Schema
+
+The wowsimcli expects complex JSON input fi
les with this hierarchy:
+
+### Top-Level Structure
+```json
+{
+  "requestId": "string",
+  "type": "SimTypeIndividual", 
+  "raid": RaidConfig,
+  "encounter": EncounterConfig,
+  "simOptions": SimulationOptions
+}
+```
+
+### Key Schema Components
+- **Raid**: Contains 5 parties (25-person r
aid), each with 5 player slots, plus raid-wi
de buffs/debuffs
+- **Player**: Complex nested structure with
 equipment (16 slots), consumables, talents,
 spec-specific options, and APL rotations
+- **Equipment**: Items with IDs, gems, ench
ants, reforging, tinkers
+- **APL (Action Priority Lists)**: Deep con
ditional logic trees for spell rotation deci
sions
+- **Encounter**: Target configuration, figh
t duration, execute phases, enemy stats
+- **Enumeration Patterns**: Prefixed types 
like "RaceBloodElf", "ClassMonk", "MobTypeMe
chanical"
+
+### Critical Details
+- Equipment items use game database IDs for
 items/gems/enchants
+- APL system uses complex nested conditions
 (and/or/cmp operators)
+- Stats arrays are fixed-length (22 element
s for target stats)
+- Empty `{}` objects serve as placeholders 
for unused slots
+- Spec-specific config uses dynamic keys li
ke `"windwalkerMonk": {...}`
+
+## Data Pipeline
+
+### Planned Workflow
+1. **Input Generation**: Nix functions crea
te JSON input files matching wowsims schema
+2. **Simulation**: wowsimcli processes inpu
ts and generates result data
+3. **Aggregation**: Results are collected i
nto static JSON files for website consumptio
n
+4. **Website**: Static site serves leaderbo
ards and trinket data
+5. **Automation**: GitHub Actions trigger u
pdates when upstream wowsims changes
+
+### Target Simulations
+- **Encounter Types**: Single Target, Multi
-Target, Short Single Target
+- **Scope**: All specs initially, trinket c
omparisons later
+- **Output**: JSON files for web frontend c
onsumption
+
+## Composable Component Design
+
+### Class Component Pattern
+The project uses a layered composition appr
oach for building reusable class configurati
ons:
+
+```nix
+{
+  lib,
+  components,
+  ...
+}: let
+  inherit (lib.sim.player) mkPlayer;
+  inherit (components.consumables) agilityD
ps;
+
+  # Spec-specific builder function
+  mkWindwalker = {
+    race,
+    apl,
+    gearset, 
+    talents,
+  }: mkPlayer {
+    class = "monk";
+    spec = "windwalker";
+    inherit race gearset talents apl;
+    consumables = agilityDps;  # Shared con
sumable set
+  };
+
+  # Organized configurations by tier and sc
enario
+  windwalker = {
+    talents = {
+      xuen = "213322";  # Single target bui
ld
+      rjw = "233321";   # AoE build
+    };
+    p1 = {
+      singleTarget = mkWindwalker {
+        race = "orc";
+        apl = "default";
+        gearset = "dw_p1_bis";
+        talents = windwalker.talents.xuen;
+      };
+      aoeOrc = mkWindwalker {
+        race = "orc";
+        apl = "default"; 
+        gearset = "dw_p1_bis";
+        talents = windwalker.talents.rjw;
+      };
+    };
+  };
+in windwalker
+```
+
+### Design Benefits
+- **Shared Defaults**: Common consumables, 
base configurations
+- **Scenario Organization**: Grouped by con
tent tier (p1, p2) and encounter type
+- **Talent Variants**: Named talent configu
rations for different playstyles
+- **Race Flexibility**: Easy to create vari
ants for different races
+- **Inheritance Chain**: `mkWindwalker` ? `
mkPlayer` ? JSON output
+
+## Working with the Code
+- Build reusable Nix components following t
he layered composition pattern
+- Create spec builders that inherit from `m
kPlayer` with sensible defaults
+- Organize configurations by content tier a
nd encounter scenario
+- Keep individual functions small and focus
ed for maintainability
+- Test changes by entering `nix develop` an
d running `wowsimcli` with generated configs
+- All simulation data comes from the refere
nced wowsims fork
+- Challenge mode can be enabled on equipmen
t for different stat scaling
+
+## Future Development
+- GitHub Actions integration for automated 
simulation updates
+- Website packaging and server configuratio
n via Nix
+- Trinket simulation expansion beyond basic
 spec rankings
\ No newline at end of file
 

diff --git a/README.md b/README.md
index 5abd3d0..5157023 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,37 @@
-WIP. This tool uses [wowsims](https://github.com/wowsims/mop)
+WIP. This tool uses [wowsims](https://github.com/wowsims/mop).
+
+Planned Features
+
+- Leaderboard for multiple encounters
+  - Long/Short Raid/Challenge mode
+    - Single target
+    - Multi target
+    - Cleave
+    - Mass AOE
+- Trinket Comparison per spec
+- 10/25 raid benchmarks
+
+# Developing
+
+- Install nix
+- run `nix develop`
+
+# Running simulations
+
+- `nix run .#<simulation>`
+
+Available simulations from [nix/apps.nix](./nix/apps.nix):
+
+- `singleTargetRaidLong`
+- `multiTargetRaidLong`
+- `cleaveRaidLong`
+- `massMultiTargetRaid`
+
+Example: `nix run .#singleTargetRaidLong`
+
+This will output a json file inside `web/public/data` that is consumed by the
+web frontend.
+
+# How it works
+
+We use nix to generate the json schema that the wowsimcli uses as input.

diff --git a/README.md b/README.md
index 5abd3d0..5157023 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,37 @@
-WIP. This tool uses [wowsims](https://githu
b.com/wowsims/mop)
+WIP. This tool uses [wowsims](https://githu
b.com/wowsims/mop).
+
+Planned Features
+
+- Leaderboard for multiple encounters
+  - Long/Short Raid/Challenge mode
+    - Single target
+    - Multi target
+    - Cleave
+    - Mass AOE
+- Trinket Comparison per spec
+- 10/25 raid benchmarks
+
+# Developing
+
+- Install nix
+- run `nix develop`
+
+# Running simulations
+
+- `nix run .#<simulation>`
+
+Available simulations from [nix/apps.nix](.
/nix/apps.nix):
+
+- `singleTargetRaidLong`
+- `multiTargetRaidLong`
+- `cleaveRaidLong`
+- `massMultiTargetRaid`
+
+Example: `nix run .#singleTargetRaidLong`
+
+This will output a json file inside `web/pu
blic/data` that is consumed by the
+web frontend.
+
+# How it works
+
+We use nix to generate the json schema that
 the wowsimcli uses as input.
 

diff --git a/nix/apps.nix b/nix/apps.nix
deleted file mode 100644
index 1c7bd8b..0000000
--- a/nix/apps.nix
+++ /dev/null
@@ -1,120 +0,0 @@
-{
-  lib,
-  classes,
-  encounter,
-  buffs,
-  debuffs,
-  inputs,
-  ...
-}: {
-  perSystem = {pkgs, ...}: let
-    # Test composition script
-    inherit (lib.sim.simulation) mkSim;
-
-    class = "druid";
-    spec = "balance";
-
-    testRaid = mkSim {
-      requestId = "raidSimAsync-f2cf5e22118a43c7";
-      iterations = 1000;
-      player = classes.${class}.${spec}.template.p1.raid.singleTarget;
-      buffs = buffs.full;
-      debuffs = debuffs.full;
-      encounter = encounter.raid.long.singleTarget;
-    };
-    testComposition = pkgs.writeShellApplication {
-      name = "test-composition";
-      text = ''
-        # Generate test elemental simulation
-        cat > ${spec}_input.json << 'EOF'
-        ${testRaid}
-        EOF
-
-        echo "Generated ${spec}_input.json"
-        echo "File size: $(wc -c < ${spec}_input.json) bytes"
-        echo "Player name: $(jq -r '.raid.parties[0].players[0].name // "missing"
' ${spec}_input.json)"
-        echo ""
-
-        echo "Running wowsimcli simulation..."
-        wowsimcli sim --infile ${spec}_input.json --outfile ${spec}_output.json
-
-        if [ -f ${spec}_output.json ]; then
-          echo "Simulation completed successfully!"
-          avgDps=$(jq -r '.raidMetrics.dps.avg' ${spec}_output.json)
-          echo "Average DPS: $avgDps"
-        else
-          echo "Error: wowsimcli failed to generate output"
-          exit 1
-        fi
-      '';
-      runtimeInputs = [pkgs.jq inputs.wowsims.packages.${pkgs.system}.wowsimcli];
-    };
-
-    # Import mass simulation
-    massSimulation = import ./mass-simulation.nix {
-      inherit lib pkgs classes encounter buffs debuffs inputs;
-    };
-
-    # Mass simulations using mkMassSim
-    mkMassSim = (import ./lib/mkMassSim.nix {inherit lib pkgs classes encounter b
uffs debuffs inputs;}).mkMassSim;
-
-    massSimulations = {
-      singleTargetRaidLong = mkMassSim {
-        specs = "dps"; # shortcut to all DPS classes templates
-        encounter = encounter.raid.long.singleTarget;
-        iterations = 10000;
-        phase = "p1";
-        encounterType = "raid";
-        targetCount = "single";
-        duration = "long";
-      };
-
-      multiTargetRaidLong = mkMassSim {
-        specs = "dps";
-        encounter = encounter.raid.long.threeTarget;
-        iterations = 10000;
-        phase = "p1";
-        encounterType = "raid";
-        targetCount = "three";
-        duration = "long";
-      };
-
-      cleaveRaidLong = mkMassSim {
-        specs = "dps";
-        encounter = encounter.raid.long.cleave;
-        iterations = 10000;
-        phase = "p1";
-        encounterType = "raid";
-        targetCount = "cleave";
-        duration = "long";
-      };
-
-      massMultiTargetRaidLong = mkMassSim {
-        specs = "dps";
-        encounter = encounter.raid.long.tenTarget;
-        iterations = 10000;
-        phase = "p1";
-        encounterType = "raid";
-        targetCount = "ten";
-        duration = "long";
-      };
-    };
-  in {
-    apps =
-      {
-        test-composition = {
-          type = "app";
-          program = "${testComposition}/bin/test-composition";
-        };
-        mass-sim = {
-          type = "app";
-          program = "${massSimulation.massSimulationScript}/bin/mass-simulation";
-        };
-      }
-      // (lib.mapAttrs (name: massSim: {
-          type = "app";
-          program = "${massSim.script}/bin/${massSim.metadata.output}-aggregator"
;
-        })
-        massSimulations);
-  };
-}

diff --git a/nix/apps.nix b/nix/apps.nix
deleted file mode 100644
index 1c7bd8b..0000000
--- a/nix/apps.nix
+++ /dev/null
@@ -1,120 +0,0 @@
-{
-  lib,
-  classes,
-  encounter,
-  buffs,
-  debuffs,
-  inputs,
-  ...
-}: {
-  perSystem = {pkgs, ...}: let
-    # Test composition script
-    inherit (lib.sim.simulation) mkSim;
-
-    class = "druid";
-    spec = "balance";
-
-    testRaid = mkSim {
-      requestId = "raidSimAsync-f2cf5e22118
a43c7";
-      iterations = 1000;
-      player = classes.${class}.${spec}.tem
plate.p1.raid.singleTarget;
-      buffs = buffs.full;
-      debuffs = debuffs.full;
-      encounter = encounter.raid.long.singl
eTarget;
-    };
-    testComposition = pkgs.writeShellApplic
ation {
-      name = "test-composition";
-      text = ''
-        # Generate test elemental simulatio
n
-        cat > ${spec}_input.json << 'EOF'
-        ${testRaid}
-        EOF
-
-        echo "Generated ${spec}_input.json"
-        echo "File size: $(wc -c < ${spec}_
input.json) bytes"
-        echo "Player name: $(jq -r '.raid.p
arties[0].players[0].name // "missing"' ${sp
ec}_input.json)"
-        echo ""
-
-        echo "Running wowsimcli simulation.
.."
-        wowsimcli sim --infile ${spec}_inpu
t.json --outfile ${spec}_output.json
-
-        if [ -f ${spec}_output.json ]; then
-          echo "Simulation completed succes
sfully!"
-          avgDps=$(jq -r '.raidMetrics.dps.
avg' ${spec}_output.json)
-          echo "Average DPS: $avgDps"
-        else
-          echo "Error: wowsimcli failed to 
generate output"
-          exit 1
-        fi
-      '';
-      runtimeInputs = [pkgs.jq inputs.wowsi
ms.packages.${pkgs.system}.wowsimcli];
-    };
-
-    # Import mass simulation
-    massSimulation = import ./mass-simulati
on.nix {
-      inherit lib pkgs classes encounter bu
ffs debuffs inputs;
-    };
-
-    # Mass simulations using mkMassSim
-    mkMassSim = (import ./lib/mkMassSim.nix
 {inherit lib pkgs classes encounter buffs d
ebuffs inputs;}).mkMassSim;
-
-    massSimulations = {
-      singleTargetRaidLong = mkMassSim {
-        specs = "dps"; # shortcut to all DP
S classes templates
-        encounter = encounter.raid.long.sin
gleTarget;
-        iterations = 10000;
-        phase = "p1";
-        encounterType = "raid";
-        targetCount = "single";
-        duration = "long";
-      };
-
-      multiTargetRaidLong = mkMassSim {
-        specs = "dps";
-        encounter = encounter.raid.long.thr
eeTarget;
-        iterations = 10000;
-        phase = "p1";
-        encounterType = "raid";
-        targetCount = "three";
-        duration = "long";
-      };
-
-      cleaveRaidLong = mkMassSim {
-        specs = "dps";
-        encounter = encounter.raid.long.cle
ave;
-        iterations = 10000;
-        phase = "p1";
-        encounterType = "raid";
-        targetCount = "cleave";
-        duration = "long";
-      };
-
-      massMultiTargetRaidLong = mkMassSim {
-        specs = "dps";
-        encounter = encounter.raid.long.ten
Target;
-        iterations = 10000;
-        phase = "p1";
-        encounterType = "raid";
-        targetCount = "ten";
-        duration = "long";
-      };
-    };
-  in {
-    apps =
-      {
-        test-composition = {
-          type = "app";
-          program = "${testComposition}/bin
/test-composition";
-        };
-        mass-sim = {
-          type = "app";
-          program = "${massSimulation.massS
imulationScript}/bin/mass-simulation";
-        };
-      }
-      // (lib.mapAttrs (name: massSim: {
-          type = "app";
-          program = "${massSim.script}/bin/
${massSim.metadata.output}-aggregator";
-        })
-        massSimulations);
-  };
-}
 

diff --git a/nix/apps/default.nix b/nix/apps/default.nix
new file mode 100644
index 0000000..65bf09e
--- /dev/null
+++ b/nix/apps/default.nix
@@ -0,0 +1,15 @@
+{
+  lib,
+  classes,
+  encounter,
+  buffs,
+  debuffs,
+  inputs,
+  ...
+}: {
+  perSystem = {pkgs, ...}: let
+    simulation = import ./simulation {inherit lib classes encounter buffs debuffs
 inputs pkgs;};
+  in {
+    apps = simulation;
+  };
+}

diff --git a/nix/apps/default.nix b/nix/apps
/default.nix
new file mode 100644
index 0000000..65bf09e
--- /dev/null
+++ b/nix/apps/default.nix
@@ -0,0 +1,15 @@
+{
+  lib,
+  classes,
+  encounter,
+  buffs,
+  debuffs,
+  inputs,
+  ...
+}: {
+  perSystem = {pkgs, ...}: let
+    simulation = import ./simulation {inher
it lib classes encounter buffs debuffs input
s pkgs;};
+  in {
+    apps = simulation;
+  };
+}
 

diff --git a/nix/apps/simulation/default.nix b/nix/apps/simulation/default.nix
new file mode 100644
index 0000000..3195272
--- /dev/null
+++ b/nix/apps/simulation/default.nix
@@ -0,0 +1,90 @@
+{
+  lib,
+  pkgs,
+  classes,
+  encounter,
+  buffs,
+  debuffs,
+  inputs,
+  ...
+}: let
+  # Mass simulations using mkMassSim
+  mkMassSim = (import ./mkMassSim.nix {inherit lib pkgs classes encounter buffs d
ebuffs inputs;}).mkMassSim;
+
+  massSimulations = {
+    dps-p1-raid-single-long = mkMassSim {
+      specs = "dps"; # shortcut to all DPS classes templates
+      encounter = encounter.raid.long.singleTarget;
+      iterations = 10000;
+      phase = "p1";
+      encounterType = "raid";
+      targetCount = "single";
+      duration = "long";
+    };
+
+    dps-p1-raid-three-long = mkMassSim {
+      specs = "dps";
+      encounter = encounter.raid.long.threeTarget;
+      iterations = 10000;
+      phase = "p1";
+      encounterType = "raid";
+      targetCount = "three";
+      duration = "long";
+    };
+
+    dps-p1-raid-cleave-long = mkMassSim {
+      specs = "dps";
+      encounter = encounter.raid.long.cleave;
+      iterations = 10000;
+      phase = "p1";
+      encounterType = "raid";
+      targetCount = "cleave";
+      duration = "long";
+    };
+
+    dps-p1-raid-ten-long = mkMassSim {
+      specs = "dps";
+      encounter = encounter.raid.long.tenTarget;
+      iterations = 10000;
+      phase = "p1";
+      encounterType = "raid";
+      targetCount = "ten";
+      duration = "long";
+    };
+  };
+
+  # Script that runs all simulations
+  allSimulationsScript = pkgs.writeShellApplication {
+    name = "all-simulations";
+    text = ''
+      echo "Running all WoW simulations..."
+
+      ${lib.concatMapStringsSep "\n" (name: ''
+        echo ""
+        echo "Running ${name}..."
+        ${massSimulations.${name}.script}/bin/${massSimulations.${name}.metadata.
output}-aggregator
+      '') (lib.attrNames massSimulations)}
+
+      echo ""
+      echo "All simulations completed successfully!"
+      echo "Generated files:"
+      ls -la web/public/data/*.json 2>/dev/null || echo "No JSON files found"
+    '';
+    runtimeInputs = [pkgs.coreutils];
+  };
+
+  # Convert mass simulations to apps and add the all-simulations app
+  simulationApps =
+    lib.mapAttrs (name: massSim: {
+      type = "app";
+      program = "${massSim.script}/bin/${massSim.metadata.output}-aggregator";
+    })
+    massSimulations;
+in
+  simulationApps
+  // {
+    allSimulations = {
+      type = "app";
+      program = "${allSimulationsScript}/bin/all-simulations";
+    };
+  }

diff --git a/nix/apps/simulation/default.nix
 b/nix/apps/simulation/default.nix
new file mode 100644
index 0000000..3195272
--- /dev/null
+++ b/nix/apps/simulation/default.nix
@@ -0,0 +1,90 @@
+{
+  lib,
+  pkgs,
+  classes,
+  encounter,
+  buffs,
+  debuffs,
+  inputs,
+  ...
+}: let
+  # Mass simulations using mkMassSim
+  mkMassSim = (import ./mkMassSim.nix {inhe
rit lib pkgs classes encounter buffs debuffs
 inputs;}).mkMassSim;
+
+  massSimulations = {
+    dps-p1-raid-single-long = mkMassSim {
+      specs = "dps"; # shortcut to all DPS 
classes templates
+      encounter = encounter.raid.long.singl
eTarget;
+      iterations = 10000;
+      phase = "p1";
+      encounterType = "raid";
+      targetCount = "single";
+      duration = "long";
+    };
+
+    dps-p1-raid-three-long = mkMassSim {
+      specs = "dps";
+      encounter = encounter.raid.long.three
Target;
+      iterations = 10000;
+      phase = "p1";
+      encounterType = "raid";
+      targetCount = "three";
+      duration = "long";
+    };
+
+    dps-p1-raid-cleave-long = mkMassSim {
+      specs = "dps";
+      encounter = encounter.raid.long.cleav
e;
+      iterations = 10000;
+      phase = "p1";
+      encounterType = "raid";
+      targetCount = "cleave";
+      duration = "long";
+    };
+
+    dps-p1-raid-ten-long = mkMassSim {
+      specs = "dps";
+      encounter = encounter.raid.long.tenTa
rget;
+      iterations = 10000;
+      phase = "p1";
+      encounterType = "raid";
+      targetCount = "ten";
+      duration = "long";
+    };
+  };
+
+  # Script that runs all simulations
+  allSimulationsScript = pkgs.writeShellApp
lication {
+    name = "all-simulations";
+    text = ''
+      echo "Running all WoW simulations..."
+
+      ${lib.concatMapStringsSep "\n" (name:
 ''
+        echo ""
+        echo "Running ${name}..."
+        ${massSimulations.${name}.script}/b
in/${massSimulations.${name}.metadata.output
}-aggregator
+      '') (lib.attrNames massSimulations)}
+
+      echo ""
+      echo "All simulations completed succe
ssfully!"
+      echo "Generated files:"
+      ls -la web/public/data/*.json 2>/dev/
null || echo "No JSON files found"
+    '';
+    runtimeInputs = [pkgs.coreutils];
+  };
+
+  # Convert mass simulations to apps and ad
d the all-simulations app
+  simulationApps =
+    lib.mapAttrs (name: massSim: {
+      type = "app";
+      program = "${massSim.script}/bin/${ma
ssSim.metadata.output}-aggregator";
+    })
+    massSimulations;
+in
+  simulationApps
+  // {
+    allSimulations = {
+      type = "app";
+      program = "${allSimulationsScript}/bi
n/all-simulations";
+    };
+  }
 

diff --git a/nix/lib/mkMassSim.nix b/nix/apps/simulation/mkMassSim.nix
similarity index 100%
rename from nix/lib/mkMassSim.nix
rename to nix/apps/simulation/mkMassSim.nix

diff --git a/nix/lib/mkMassSim.nix b/nix/app
s/simulation/mkMassSim.nix
similarity index 100%
rename from nix/lib/mkMassSim.nix
rename to nix/apps/simulation/mkMassSim.nix
 

diff --git a/nix/default.nix b/nix/default.nix
index 44d9a28..d353f15 100644
--- a/nix/default.nix
+++ b/nix/default.nix
@@ -1,8 +1,9 @@
 {
   imports = [
     ./shell.nix
-    ./apps.nix
+    ./apps
     ./checks.nix
+    ./pkgs
 
     # components
     ./classes

diff --git a/nix/default.nix b/nix/default.n
ix
index 44d9a28..d353f15 100644
--- a/nix/default.nix
+++ b/nix/default.nix
@@ -1,8 +1,9 @@
 {
   imports = [
     ./shell.nix
-    ./apps.nix
+    ./apps
     ./checks.nix
+    ./pkgs
 
     # components
     ./classes
 

diff --git a/nix/lib/mass-sim.nix b/nix/lib/mass-sim.nix
deleted file mode 100644
index 5b00bba..0000000
--- a/nix/lib/mass-sim.nix
+++ /dev/null
@@ -1,165 +0,0 @@
-{
-  lib,
-  pkgs,
-  classes,
-  encounter,
-  buffs,
-  debuffs,
-  ...
-}: let
-  inherit (lib.sim.simulation) mkSim;
-
-  # Helper to get all available class/spec combinations for a given encounter typ
e
-  getAllSpecConfigs = encounterCategory: targetType: duration: classes:
-    lib.flatten (lib.mapAttrsToList (
-        className: classSpecs:
-          lib.mapAttrsToList (
-            specName: specConfigs:
-              if
-                lib.hasAttr "template" specConfigs
-                && lib.hasAttr "p1" specConfigs.template
-                && lib.hasAttr encounterCategory specConfigs.template.p1
-                && lib.hasAttr targetType specConfigs.template.p1.${encounterCate
gory}
-              then {
-                inherit className specName;
-                config = specConfigs.template.p1.${encounterCategory}.${targetTyp
e};
-              }
-              else null
-          )
-          classSpecs
-      )
-      classes);
-
-  # Filter out null values
-  filterValidConfigs = configs: lib.filter (x: x != null) configs;
-
-  # Create simulation input for a specific spec
-  createSimInput = {
-    className,
-    specName,
-    config,
-    encounterType,
-    encounterCategory,
-    targetType,
-    duration,
-  }:
-    mkSim {
-      requestId = "mass-sim-${className}-${specName}-${encounterCategory}-${targe
tType}-${duration}";
-      iterations = 1000;
-      player = config;
-      buffs = buffs.full;
-      debuffs = debuffs.full;
-      encounter = encounter.${encounterCategory}.${duration}.${targetType};
-    };
-
-  # Mass simulation function
-  mkMassSimulation = {
-    encounterCategory ? "raid",
-    targetType ? "singleTarget",
-    duration ? "long",
-  }: let
-    # Get all valid spec configurations
-    allSpecs = filterValidConfigs (getAllSpecConfigs encounterCategory targetType
 duration classes);
-
-    # Create individual simulation derivations
-    simDerivations = lib.listToAttrs (map (spec: {
-        name = "${spec.className}-${spec.specName}";
-        value = let
-          simInput = createSimInput {
-            inherit (spec) className specName config;
-            encounterType = encounterCategory;
-            inherit encounterCategory targetType duration;
-          };
-        in
-          pkgs.runCommand "sim-${spec.className}-${spec.specName}" {
-            buildInputs = [pkgs.jq];
-            nativeBuildInputs = [pkgs.wowsimcli];
-          } ''
-            # Create input file
-            cat > input.json << 'EOF'
-            ${simInput}
-            EOF
-
-            # Run simulation
-            wowsimcli sim --infile input.json --outfile output.json
-
-            # Extract DPS and create result JSON
-            avgDps=$(jq -r '.raidMetrics.dps.avg // 0' output.json)
-
-            # Create output with DPS and loadout info
-            jq -n --arg dps "$avgDps" --arg className "${spec.className}" --arg s
pecName "${spec.specName}" \
-               --argjson loadout '${builtins.toJSON spec.config}' \
-               '{
-                 dps: ($dps | tonumber),
-                 className: $className,
-                 specName: $specName,
-                 loadout: $loadout
-               }' > $out
-          '';
-      })
-      allSpecs);
-
-    # Aggregate all results into final JSON structure
-    aggregatedResults =
-      pkgs.runCommand "mass-sim-${encounterCategory}-${targetType}-${duration}" {
-        buildInputs = [pkgs.jq];
-      } ''
-        # Create the nested JSON structure
-        jq -n --argjson specs '{}' \
-          '{ "${encounterCategory}": { "${targetType}": { "${duration}": $specs }
 } }' > result.json
-
-        ${lib.concatMapStringsSep "\n" (spec: ''
-            # Read result for ${spec.className}/${spec.specName}
-            specResult=$(cat ${simDerivations."${spec.className}-${spec.specName}
"})
-
-            # Add to the nested structure
-            jq --argjson spec "$specResult" \
-               '.${encounterCategory}.${targetType}.${duration}."${spec.className
}"."${spec.specName}" = {
-                 dps: $spec.dps,
-                 loadout: $spec.loadout
-               }' result.json > temp.json && mv temp.json result.json
-          '')
-          allSpecs}
-
-        # Final output
-        cp result.json $out
-      '';
-  in {
-    # Individual simulation results
-    simulations = simDerivations;
-
-    # Aggregated JSON output
-    result = aggregatedResults;
-
-    # Metadata
-    metadata = {
-      inherit encounterCategory targetType duration;
-      specCount = lib.length allSpecs;
-      specs = map (s: "${s.className}/${s.specName}") allSpecs;
-    };
-  };
-in {
-  inherit mkMassSimulation;
-
-  # Pre-defined common simulation sets
-  presets = {
-    raidSingleTargetLong = mkMassSimulation {
-      encounterCategory = "raid";
-      targetType = "singleTarget";
-      duration = "long";
-    };
-
-    raidMultiTargetLong = mkMassSimulation {
-      encounterCategory = "raid";
-      targetType = "multiTarget";
-      duration = "long";
-    };
-
-    raidCleaveLong = mkMassSimulation {
-      encounterCategory = "raid";
-      targetType = "cleave";
-      duration = "long";
-    };
-  };
-}
-

diff --git a/nix/lib/mass-sim.nix b/nix/lib/
mass-sim.nix
deleted file mode 100644
index 5b00bba..0000000
--- a/nix/lib/mass-sim.nix
+++ /dev/null
@@ -1,165 +0,0 @@
-{
-  lib,
-  pkgs,
-  classes,
-  encounter,
-  buffs,
-  debuffs,
-  ...
-}: let
-  inherit (lib.sim.simulation) mkSim;
-
-  # Helper to get all available class/spec 
combinations for a given encounter type
-  getAllSpecConfigs = encounterCategory: ta
rgetType: duration: classes:
-    lib.flatten (lib.mapAttrsToList (
-        className: classSpecs:
-          lib.mapAttrsToList (
-            specName: specConfigs:
-              if
-                lib.hasAttr "template" spec
Configs
-                && lib.hasAttr "p1" specCon
figs.template
-                && lib.hasAttr encounterCat
egory specConfigs.template.p1
-                && lib.hasAttr targetType s
pecConfigs.template.p1.${encounterCategory}
-              then {
-                inherit className specName;
-                config = specConfigs.templa
te.p1.${encounterCategory}.${targetType};
-              }
-              else null
-          )
-          classSpecs
-      )
-      classes);
-
-  # Filter out null values
-  filterValidConfigs = configs: lib.filter 
(x: x != null) configs;
-
-  # Create simulation input for a specific 
spec
-  createSimInput = {
-    className,
-    specName,
-    config,
-    encounterType,
-    encounterCategory,
-    targetType,
-    duration,
-  }:
-    mkSim {
-      requestId = "mass-sim-${className}-${
specName}-${encounterCategory}-${targetType}
-${duration}";
-      iterations = 1000;
-      player = config;
-      buffs = buffs.full;
-      debuffs = debuffs.full;
-      encounter = encounter.${encounterCate
gory}.${duration}.${targetType};
-    };
-
-  # Mass simulation function
-  mkMassSimulation = {
-    encounterCategory ? "raid",
-    targetType ? "singleTarget",
-    duration ? "long",
-  }: let
-    # Get all valid spec configurations
-    allSpecs = filterValidConfigs (getAllSp
ecConfigs encounterCategory targetType durat
ion classes);
-
-    # Create individual simulation derivati
ons
-    simDerivations = lib.listToAttrs (map (
spec: {
-        name = "${spec.className}-${spec.sp
ecName}";
-        value = let
-          simInput = createSimInput {
-            inherit (spec) className specNa
me config;
-            encounterType = encounterCatego
ry;
-            inherit encounterCategory targe
tType duration;
-          };
-        in
-          pkgs.runCommand "sim-${spec.class
Name}-${spec.specName}" {
-            buildInputs = [pkgs.jq];
-            nativeBuildInputs = [pkgs.wowsi
mcli];
-          } ''
-            # Create input file
-            cat > input.json << 'EOF'
-            ${simInput}
-            EOF
-
-            # Run simulation
-            wowsimcli sim --infile input.js
on --outfile output.json
-
-            # Extract DPS and create result
 JSON
-            avgDps=$(jq -r '.raidMetrics.dp
s.avg // 0' output.json)
-
-            # Create output with DPS and lo
adout info
-            jq -n --arg dps "$avgDps" --arg
 className "${spec.className}" --arg specNam
e "${spec.specName}" \
-               --argjson loadout '${builtin
s.toJSON spec.config}' \
-               '{
-                 dps: ($dps | tonumber),
-                 className: $className,
-                 specName: $specName,
-                 loadout: $loadout
-               }' > $out
-          '';
-      })
-      allSpecs);
-
-    # Aggregate all results into final JSON
 structure
-    aggregatedResults =
-      pkgs.runCommand "mass-sim-${encounter
Category}-${targetType}-${duration}" {
-        buildInputs = [pkgs.jq];
-      } ''
-        # Create the nested JSON structure
-        jq -n --argjson specs '{}' \
-          '{ "${encounterCategory}": { "${t
argetType}": { "${duration}": $specs } } }' 
> result.json
-
-        ${lib.concatMapStringsSep "\n" (spe
c: ''
-            # Read result for ${spec.classN
ame}/${spec.specName}
-            specResult=$(cat ${simDerivatio
ns."${spec.className}-${spec.specName}"})
-
-            # Add to the nested structure
-            jq --argjson spec "$specResult"
 \
-               '.${encounterCategory}.${tar
getType}.${duration}."${spec.className}"."${
spec.specName}" = {
-                 dps: $spec.dps,
-                 loadout: $spec.loadout
-               }' result.json > temp.json &
& mv temp.json result.json
-          '')
-          allSpecs}
-
-        # Final output
-        cp result.json $out
-      '';
-  in {
-    # Individual simulation results
-    simulations = simDerivations;
-
-    # Aggregated JSON output
-    result = aggregatedResults;
-
-    # Metadata
-    metadata = {
-      inherit encounterCategory targetType 
duration;
-      specCount = lib.length allSpecs;
-      specs = map (s: "${s.className}/${s.s
pecName}") allSpecs;
-    };
-  };
-in {
-  inherit mkMassSimulation;
-
-  # Pre-defined common simulation sets
-  presets = {
-    raidSingleTargetLong = mkMassSimulation
 {
-      encounterCategory = "raid";
-      targetType = "singleTarget";
-      duration = "long";
-    };
-
-    raidMultiTargetLong = mkMassSimulation 
{
-      encounterCategory = "raid";
-      targetType = "multiTarget";
-      duration = "long";
-    };
-
-    raidCleaveLong = mkMassSimulation {
-      encounterCategory = "raid";
-      targetType = "cleave";
-      duration = "long";
-    };
-  };
-}
-
 

diff --git a/nix/pkgs/default.nix b/nix/pkgs/default.nix
new file mode 100644
index 0000000..a706234
--- /dev/null
+++ b/nix/pkgs/default.nix
@@ -0,0 +1,23 @@
+{
+  lib,
+  classes,
+  encounter,
+  buffs,
+  debuffs,
+  ...
+}: {
+  perSystem = {
+    pkgs,
+    inputs',
+    ...
+  }: let
+    inherit (pkgs) callPackage;
+    inherit (inputs'.wowsims.packages) wowsimcli;
+  in {
+    packages = {
+      testRaid = callPackage ./testRaid.nix {
+        inherit lib classes encounter buffs debuffs wowsimcli;
+      };
+    };
+  };
+}

diff --git a/nix/pkgs/default.nix b/nix/pkgs
/default.nix
new file mode 100644
index 0000000..a706234
--- /dev/null
+++ b/nix/pkgs/default.nix
@@ -0,0 +1,23 @@
+{
+  lib,
+  classes,
+  encounter,
+  buffs,
+  debuffs,
+  ...
+}: {
+  perSystem = {
+    pkgs,
+    inputs',
+    ...
+  }: let
+    inherit (pkgs) callPackage;
+    inherit (inputs'.wowsims.packages) wows
imcli;
+  in {
+    packages = {
+      testRaid = callPackage ./testRaid.nix
 {
+        inherit lib classes encounter buffs
 debuffs wowsimcli;
+      };
+    };
+  };
+}
 

diff --git a/nix/pkgs/pkgs.nix b/nix/pkgs/pkgs.nix
deleted file mode 100644
index 7300efe..0000000
--- a/nix/pkgs/pkgs.nix
+++ /dev/null
@@ -1,24 +0,0 @@
-{self, ...}: {
-  perSystem = {
-    pkgs,
-    self',
-    lib,
-    ...
-  }: let
-    inherit (lib) getExe;
-  in {
-    packages.default = pkgs.stdenvNoCC.mkDerivation {
-      pname = "my package";
-      version = "0.1.0";
-      src = "${self}/src";
-      nativeBuildInputs = [];
-
-      buildPhase = "";
-      dontInstall = true;
-    };
-    apps.default = {
-      type = "app";
-      program = "${getExe self'.packages.default}";
-    };
-  };
-}

diff --git a/nix/pkgs/pkgs.nix b/nix/pkgs/pk
gs.nix
deleted file mode 100644
index 7300efe..0000000
--- a/nix/pkgs/pkgs.nix
+++ /dev/null
@@ -1,24 +0,0 @@
-{self, ...}: {
-  perSystem = {
-    pkgs,
-    self',
-    lib,
-    ...
-  }: let
-    inherit (lib) getExe;
-  in {
-    packages.default = pkgs.stdenvNoCC.mkDe
rivation {
-      pname = "my package";
-      version = "0.1.0";
-      src = "${self}/src";
-      nativeBuildInputs = [];
-
-      buildPhase = "";
-      dontInstall = true;
-    };
-    apps.default = {
-      type = "app";
-      program = "${getExe self'.packages.de
fault}";
-    };
-  };
-}
 

diff --git a/nix/pkgs/rankings.nix b/nix/pkgs/rankings.nix
deleted file mode 100644
index 48a557f..0000000
--- a/nix/pkgs/rankings.nix
+++ /dev/null
@@ -1,106 +0,0 @@
-{
-  writeShellApplication,
-  wowsimcli,
-  jq,
-  self,
-  lib,
-  ...
-}: let
-  classConfigs = import ./utils/classConfigs.nix {inherit lib self;};
-
-  # Test the new generateSimulation function
-  testInfile = classConfigs.generateSimulation 
-    classConfigs.monk.windwalker.singleTarget 
-    classConfigs.encounters.long.singleTarget;
-    
-  # Test challenge mode
-  testChallengeModeInfile = classConfigs.generateSimulation 
-    classConfigs.monk.windwalker.challengeMode 
-    classConfigs.encounters.long.singleTarget;
-in
-  writeShellApplication {
-    name = "generate-rankings";
-    runtimeInputs = [
-      wowsimcli
-      jq
-    ];
-    text = ''
-      set -euo pipefail
-
-      echo "Testing class configuration system..."
-
-      # Generate different configurations
-      echo "1. Monk Windwalker Single Target (Long):"
-      cat > "./monk_windwalker_st_long.json" << 'EOF'
-        ${testInfile}
-      EOF
-      
-      echo "? Generated: monk_windwalker_st_long.json"
-      echo "File size: $(du -h "./monk_windwalker_st_long.json" | cut -f1)"
-      
-      echo ""
-      echo "2. Monk Windwalker Challenge Mode:"
-      cat > "./monk_windwalker_challenge_mode.json" << 'EOF'
-        ${testChallengeModeInfile}
-      EOF
-      
-      echo "? Generated: monk_windwalker_challenge_mode.json"
-      echo "File size: $(du -h "./monk_windwalker_challenge_mode.json" | cut -f1)
"
-
-      # Test JSON validation
-      echo ""
-      echo "JSON validation:"
-      if jq empty "./monk_windwalker_st_long.json" 2>/dev/null && jq empty "./mon
k_windwalker_challenge_mode.json" 2>/dev/null; then
-        echo "? Both files have valid JSON"
-      else
-        echo "? Invalid JSON found"
-        echo "Standard mode errors:"
-        jq empty "./monk_windwalker_st_long.json"
-        echo "Challenge mode errors:"
-        jq empty "./monk_windwalker_challenge_mode.json"
-      fi
-
-      echo ""
-      echo "Configuration demonstrates:"
-      echo "Standard Mode:"
-      echo "- Class: $(jq -r '.raid.parties[0].players[0].class' "./monk_windwalk
er_st_long.json")"
-      echo "- Spec field: $(jq -r '. | keys | .[] | select(. == "windwalkerMonk")
' "./monk_windwalker_st_long.json" || echo "windwalkerMonk")"
-      echo "- Encounter duration: $(jq -r '.encounter.duration' "./monk_windwalke
r_st_long.json")s"
-      echo "- Target count: $(jq -r '.encounter.targets | length' "./monk_windwal
ker_st_long.json")"
-      echo "- Raid buffs enabled: $(jq -r '.raid.buffs | [to_entries[] | select(.
value == true) | .key] | length' "./monk_windwalker_st_long.json")"
-      echo "- Challenge mode items: $(jq -r '.raid.parties[0].players[0].equipmen
t.items | map(select(.challengeMode == true)) | length' "./monk_windwalker_st_long
.json")"
-      echo ""
-      echo "Challenge Mode:"
-      echo "- Challenge mode items: $(jq -r '.raid.parties[0].players[0].equipmen
t.items | map(select(.challengeMode == true)) | length' "./monk_windwalker_challen
ge_mode.json")"
-      echo "- Total equipment items: $(jq -r '.raid.parties[0].players[0].equipme
nt.items | length' "./monk_windwalker_challenge_mode.json")"
-
-      echo ""
-      echo "Usage examples:"
-      echo "  classConfigs.generateSimulation classConfigs.monk.windwalker.single
Target classConfigs.encounters.long.singleTarget"
-      echo "  classConfigs.generateSimulation classConfigs.monk.windwalker.multiT
arget classConfigs.encounters.short.multiTarget8"
-      echo "  classConfigs.generateSimulation classConfigs.monk.windwalker.challe
ngeMode classConfigs.encounters.long.singleTarget"
-      echo "  classConfigs.generateSimulation classConfigs.monk.windwalker.challe
ngeModeMultiTarget classConfigs.encounters.short.multiTarget8"
-      echo ""
-      echo "Available encounters:"
-      echo "  - encounters.long.singleTarget"
-      echo "  - encounters.long.multiTarget2"
-      echo "  - encounters.long.multiTarget8"
-      echo "  - encounters.short.singleTarget"
-      echo "  - encounters.short.multiTarget2"
-      echo "  - encounters.short.multiTarget8"
-      echo "  - encounters.patchwerk.long"
-      echo "  - encounters.cleave.short"
-      echo "  - encounters.aoe.long"
-      echo ""
-      echo "Available raid buff presets:"
-      echo "  - raidBuffs.fullBuffs (all buffs including bloodlust)"
-      echo "  - raidBuffs.fullBuffsNoLust (all buffs except bloodlust)"
-      echo "  - raidBuffs.noBuffs (no buffs)"
-      echo "  - raidBuffs.mergeRaidBuffs {bloodlust = false; trueshotAura = false
;} (custom)"
-      echo ""
-      echo "Available raid debuff presets:"
-      echo "  - raidDebuffs.fullDebuffs (all debuffs)"
-      echo "  - raidDebuffs.noDebuffs (no debuffs)"
-      echo "  - raidDebuffs.mergeRaidDebuffs {physicalVulnerability = false;} (cu
stom)"
-    '';
-  }

diff --git a/nix/pkgs/rankings.nix b/nix/pkg
s/rankings.nix
deleted file mode 100644
index 48a557f..0000000
--- a/nix/pkgs/rankings.nix
+++ /dev/null
@@ -1,106 +0,0 @@
-{
-  writeShellApplication,
-  wowsimcli,
-  jq,
-  self,
-  lib,
-  ...
-}: let
-  classConfigs = import ./utils/classConfig
s.nix {inherit lib self;};
-
-  # Test the new generateSimulation functio
n
-  testInfile = classConfigs.generateSimulat
ion 
-    classConfigs.monk.windwalker.singleTarg
et 
-    classConfigs.encounters.long.singleTarg
et;
-    
-  # Test challenge mode
-  testChallengeModeInfile = classConfigs.ge
nerateSimulation 
-    classConfigs.monk.windwalker.challengeM
ode 
-    classConfigs.encounters.long.singleTarg
et;
-in
-  writeShellApplication {
-    name = "generate-rankings";
-    runtimeInputs = [
-      wowsimcli
-      jq
-    ];
-    text = ''
-      set -euo pipefail
-
-      echo "Testing class configuration sys
tem..."
-
-      # Generate different configurations
-      echo "1. Monk Windwalker Single Targe
t (Long):"
-      cat > "./monk_windwalker_st_long.json
" << 'EOF'
-        ${testInfile}
-      EOF
-      
-      echo "? Generated: monk_windwalker_st
_long.json"
-      echo "File size: $(du -h "./monk_wind
walker_st_long.json" | cut -f1)"
-      
-      echo ""
-      echo "2. Monk Windwalker Challenge Mo
de:"
-      cat > "./monk_windwalker_challenge_mo
de.json" << 'EOF'
-        ${testChallengeModeInfile}
-      EOF
-      
-      echo "? Generated: monk_windwalker_ch
allenge_mode.json"
-      echo "File size: $(du -h "./monk_wind
walker_challenge_mode.json" | cut -f1)"
-
-      # Test JSON validation
-      echo ""
-      echo "JSON validation:"
-      if jq empty "./monk_windwalker_st_lon
g.json" 2>/dev/null && jq empty "./monk_wind
walker_challenge_mode.json" 2>/dev/null; the
n
-        echo "? Both files have valid JSON"
-      else
-        echo "? Invalid JSON found"
-        echo "Standard mode errors:"
-        jq empty "./monk_windwalker_st_long
.json"
-        echo "Challenge mode errors:"
-        jq empty "./monk_windwalker_challen
ge_mode.json"
-      fi
-
-      echo ""
-      echo "Configuration demonstrates:"
-      echo "Standard Mode:"
-      echo "- Class: $(jq -r '.raid.parties
[0].players[0].class' "./monk_windwalker_st_
long.json")"
-      echo "- Spec field: $(jq -r '. | keys
 | .[] | select(. == "windwalkerMonk")' "./m
onk_windwalker_st_long.json" || echo "windwa
lkerMonk")"
-      echo "- Encounter duration: $(jq -r '
.encounter.duration' "./monk_windwalker_st_l
ong.json")s"
-      echo "- Target count: $(jq -r '.encou
nter.targets | length' "./monk_windwalker_st
_long.json")"
-      echo "- Raid buffs enabled: $(jq -r '
.raid.buffs | [to_entries[] | select(.value 
== true) | .key] | length' "./monk_windwalke
r_st_long.json")"
-      echo "- Challenge mode items: $(jq -r
 '.raid.parties[0].players[0].equipment.item
s | map(select(.challengeMode == true)) | le
ngth' "./monk_windwalker_st_long.json")"
-      echo ""
-      echo "Challenge Mode:"
-      echo "- Challenge mode items: $(jq -r
 '.raid.parties[0].players[0].equipment.item
s | map(select(.challengeMode == true)) | le
ngth' "./monk_windwalker_challenge_mode.json
")"
-      echo "- Total equipment items: $(jq -
r '.raid.parties[0].players[0].equipment.ite
ms | length' "./monk_windwalker_challenge_mo
de.json")"
-
-      echo ""
-      echo "Usage examples:"
-      echo "  classConfigs.generateSimulati
on classConfigs.monk.windwalker.singleTarget
 classConfigs.encounters.long.singleTarget"
-      echo "  classConfigs.generateSimulati
on classConfigs.monk.windwalker.multiTarget 
classConfigs.encounters.short.multiTarget8"
-      echo "  classConfigs.generateSimulati
on classConfigs.monk.windwalker.challengeMod
e classConfigs.encounters.long.singleTarget"
-      echo "  classConfigs.generateSimulati
on classConfigs.monk.windwalker.challengeMod
eMultiTarget classConfigs.encounters.short.m
ultiTarget8"
-      echo ""
-      echo "Available encounters:"
-      echo "  - encounters.long.singleTarge
t"
-      echo "  - encounters.long.multiTarget
2"
-      echo "  - encounters.long.multiTarget
8"
-      echo "  - encounters.short.singleTarg
et"
-      echo "  - encounters.short.multiTarge
t2"
-      echo "  - encounters.short.multiTarge
t8"
-      echo "  - encounters.patchwerk.long"
-      echo "  - encounters.cleave.short"
-      echo "  - encounters.aoe.long"
-      echo ""
-      echo "Available raid buff presets:"
-      echo "  - raidBuffs.fullBuffs (all bu
ffs including bloodlust)"
-      echo "  - raidBuffs.fullBuffsNoLust (
all buffs except bloodlust)"
-      echo "  - raidBuffs.noBuffs (no buffs
)"
-      echo "  - raidBuffs.mergeRaidBuffs {b
loodlust = false; trueshotAura = false;} (cu
stom)"
-      echo ""
-      echo "Available raid debuff presets:"
-      echo "  - raidDebuffs.fullDebuffs (al
l debuffs)"
-      echo "  - raidDebuffs.noDebuffs (no d
ebuffs)"
-      echo "  - raidDebuffs.mergeRaidDebuff
s {physicalVulnerability = false;} (custom)"
-    '';
-  }
 

diff --git a/nix/pkgs/testRaid.nix b/nix/pkgs/testRaid.nix
new file mode 100644
index 0000000..6ab0f7a
--- /dev/null
+++ b/nix/pkgs/testRaid.nix
@@ -0,0 +1,53 @@
+{
+  wowsimcli,
+  jq,
+  writeShellApplication,
+  lib,
+  classes,
+  encounter,
+  buffs,
+  debuffs,
+  ...
+}: let
+  # quickly sim a single spec for testing purposes
+  inherit (lib.sim.simulation) mkSim;
+
+  class = "druid";
+  spec = "balance";
+
+  raid = mkSim {
+    requestId = "raidSimAsync-f2cf5e22118a43c7";
+    iterations = 1000;
+    player = classes.${class}.${spec}.template.p1.raid.singleTarget;
+    buffs = buffs.full;
+    debuffs = debuffs.full;
+    encounter = encounter.raid.long.singleTarget;
+  };
+  testRaid = writeShellApplication {
+    name = "testRaid";
+    text = ''
+      cat > ${spec}_input.json << 'EOF'
+      ${raid}
+      EOF
+
+      echo "Generated ${spec}_input.json"
+      echo "File size: $(wc -c < ${spec}_input.json) bytes"
+      echo "Player name: $(jq -r '.raid.parties[0].players[0].name // "missing"' 
${spec}_input.json)"
+      echo ""
+
+      echo "Running wowsimcli simulation..."
+      wowsimcli sim --infile ${spec}_input.json --outfile ${spec}_output.json
+
+      if [ -f ${spec}_output.json ]; then
+        echo "Simulation completed successfully!"
+        avgDps=$(jq -r '.raidMetrics.dps.avg' ${spec}_output.json)
+        echo "Average DPS: $avgDps"
+      else
+        echo "Error: wowsimcli failed to generate output"
+        exit 1
+      fi
+    '';
+    runtimeInputs = [jq wowsimcli];
+  };
+in
+  testRaid

diff --git a/nix/pkgs/testRaid.nix b/nix/pkg
s/testRaid.nix
new file mode 100644
index 0000000..6ab0f7a
--- /dev/null
+++ b/nix/pkgs/testRaid.nix
@@ -0,0 +1,53 @@
+{
+  wowsimcli,
+  jq,
+  writeShellApplication,
+  lib,
+  classes,
+  encounter,
+  buffs,
+  debuffs,
+  ...
+}: let
+  # quickly sim a single spec for testing p
urposes
+  inherit (lib.sim.simulation) mkSim;
+
+  class = "druid";
+  spec = "balance";
+
+  raid = mkSim {
+    requestId = "raidSimAsync-f2cf5e22118a4
3c7";
+    iterations = 1000;
+    player = classes.${class}.${spec}.templ
ate.p1.raid.singleTarget;
+    buffs = buffs.full;
+    debuffs = debuffs.full;
+    encounter = encounter.raid.long.singleT
arget;
+  };
+  testRaid = writeShellApplication {
+    name = "testRaid";
+    text = ''
+      cat > ${spec}_input.json << 'EOF'
+      ${raid}
+      EOF
+
+      echo "Generated ${spec}_input.json"
+      echo "File size: $(wc -c < ${spec}_in
put.json) bytes"
+      echo "Player name: $(jq -r '.raid.par
ties[0].players[0].name // "missing"' ${spec
}_input.json)"
+      echo ""
+
+      echo "Running wowsimcli simulation...
"
+      wowsimcli sim --infile ${spec}_input.
json --outfile ${spec}_output.json
+
+      if [ -f ${spec}_output.json ]; then
+        echo "Simulation completed successf
ully!"
+        avgDps=$(jq -r '.raidMetrics.dps.av
g' ${spec}_output.json)
+        echo "Average DPS: $avgDps"
+      else
+        echo "Error: wowsimcli failed to ge
nerate output"
+        exit 1
+      fi
+    '';
+    runtimeInputs = [jq wowsimcli];
+  };
+in
+  testRaid
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET