OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      cfce745448cd
DATE      2025-07-18
SUBJECT   inital commit
FILES     13 CHANGED
HASH      cfce745448cd
DATE      2025-07-18
SUBJECT   inital commit
FILES     13 CHANGED
 

diff --git a/.envrc b/.envrc
new file mode 100644
index 0000000..3550a30
--- /dev/null
+++ b/.envrc
@@ -0,0 +1 @@
+use flake

diff --git a/.envrc b/.envrc
new file mode 100644
index 0000000..3550a30
--- /dev/null
+++ b/.envrc
@@ -0,0 +1 @@
+use flake
 

diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..7825c71
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,105 @@
+{
+  "nodes": {
+    "flake-parts": {
+      "inputs": {
+        "nixpkgs-lib": "nixpkgs-lib"
+      },
+      "locked": {
+        "lastModified": 1751413152,
+        "narHash": "sha256-Tyw1RjYEsp5scoigs1384gIg6e0GoBVjms4aXFfRssQ=",
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "rev": "77826244401ea9de6e3bac47c2db46005e1f30b5",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "type": "github"
+      }
+    },
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1752687322,
+        "narHash": "sha256-RKwfXA4OZROjBTQAl9WOZQFm7L8Bo93FQwSJpAiSRvo=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "6e987485eb2c77e5dcc5af4e3c70843711ef9251",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs-lib": {
+      "locked": {
+        "lastModified": 1751159883,
+        "narHash": "sha256-urW/Ylk9FIfvXfliA1ywh75yszAbiTEVgpPeinFyVZo=",
+        "owner": "nix-community",
+        "repo": "nixpkgs.lib",
+        "rev": "14a40a1d7fb9afa4739275ac642ed7301a9ba1ab",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "repo": "nixpkgs.lib",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "flake-parts": "flake-parts",
+        "nixpkgs": "nixpkgs",
+        "systems": "systems",
+        "wowsims": "wowsims"
+      }
+    },
+    "systems": {
+      "locked": {
+        "lastModified": 1689347949,
+        "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
+        "owner": "nix-systems",
+        "repo": "default-linux",
+        "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default-linux",
+        "type": "github"
+      }
+    },
+    "wowsims": {
+      "inputs": {
+        "flake-parts": [
+          "flake-parts"
+        ],
+        "nixpkgs": [
+          "nixpkgs"
+        ],
+        "systems": [
+          "systems"
+        ]
+      },
+      "locked": {
+        "lastModified": 1752842605,
+        "narHash": "sha256-AN7DxySgSMHeXw9s1fIZyVK+TrAJXJDFFdN+Rr3jp4s=",
+        "owner": "ooks-io",
+        "repo": "mop",
+        "rev": "e1f2d6f688c0f86a2193dda8d8cd7c146a64ddd5",
+        "type": "github"
+      },
+      "original": {
+        "owner": "ooks-io",
+        "ref": "nix",
+        "repo": "mop",
+        "type": "github"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}

diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..7825c71
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,105 @@
+{
+  "nodes": {
+    "flake-parts": {
+      "inputs": {
+        "nixpkgs-lib": "nixpkgs-lib"
+      },
+      "locked": {
+        "lastModified": 1751413152,
+        "narHash": "sha256-Tyw1RjYEsp5scoig
s1384gIg6e0GoBVjms4aXFfRssQ=",
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "rev": "77826244401ea9de6e3bac47c2d
b46005e1f30b5",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "type": "github"
+      }
+    },
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1752687322,
+        "narHash": "sha256-RKwfXA4OZROjBTQA
l9WOZQFm7L8Bo93FQwSJpAiSRvo=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "6e987485eb2c77e5dcc5af4e3c7
0843711ef9251",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs-lib": {
+      "locked": {
+        "lastModified": 1751159883,
+        "narHash": "sha256-urW/Ylk9FIfvXfli
A1ywh75yszAbiTEVgpPeinFyVZo=",
+        "owner": "nix-community",
+        "repo": "nixpkgs.lib",
+        "rev": "14a40a1d7fb9afa4739275ac642
ed7301a9ba1ab",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "repo": "nixpkgs.lib",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "flake-parts": "flake-parts",
+        "nixpkgs": "nixpkgs",
+        "systems": "systems",
+        "wowsims": "wowsims"
+      }
+    },
+    "systems": {
+      "locked": {
+        "lastModified": 1689347949,
+        "narHash": "sha256-12tWmuL2zgBgZkdo
B6qXZsgJEH9LR3oUgpaQq2RbI80=",
+        "owner": "nix-systems",
+        "repo": "default-linux",
+        "rev": "31732fcf5e8fea42e59c2488ad3
1a0e651500f68",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default-linux",
+        "type": "github"
+      }
+    },
+    "wowsims": {
+      "inputs": {
+        "flake-parts": [
+          "flake-parts"
+        ],
+        "nixpkgs": [
+          "nixpkgs"
+        ],
+        "systems": [
+          "systems"
+        ]
+      },
+      "locked": {
+        "lastModified": 1752842605,
+        "narHash": "sha256-AN7DxySgSMHeXw9s
1fIZyVK+TrAJXJDFFdN+Rr3jp4s=",
+        "owner": "ooks-io",
+        "repo": "mop",
+        "rev": "e1f2d6f688c0f86a2193dda8d8c
d7c146a64ddd5",
+        "type": "github"
+      },
+      "original": {
+        "owner": "ooks-io",
+        "ref": "nix",
+        "repo": "mop",
+        "type": "github"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
 

diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..fd4a593
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,23 @@
+{
+  description = "Description for the project";
+
+  inputs = {
+    flake-parts.url = "github:hercules-ci/flake-parts";
+    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
+    systems.url = "github:nix-systems/default-linux";
+    wowsims = {
+      url = "github:ooks-io/mop/nix";
+      inputs = {
+        nixpkgs.follows = "nixpkgs";
+        flake-parts.follows = "flake-parts";
+        systems.follows = "systems";
+      };
+    };
+  };
+
+  outputs = inputs @ {flake-parts, ...}:
+    flake-parts.lib.mkFlake {inherit inputs;} {
+      systems = import inputs.systems;
+      imports = [./nix];
+    };
+}

diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..fd4a593
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,23 @@
+{
+  description = "Description for the projec
t";
+
+  inputs = {
+    flake-parts.url = "github:hercules-ci/f
lake-parts";
+    nixpkgs.url = "github:NixOS/nixpkgs/nix
os-unstable";
+    systems.url = "github:nix-systems/defau
lt-linux";
+    wowsims = {
+      url = "github:ooks-io/mop/nix";
+      inputs = {
+        nixpkgs.follows = "nixpkgs";
+        flake-parts.follows = "flake-parts"
;
+        systems.follows = "systems";
+      };
+    };
+  };
+
+  outputs = inputs @ {flake-parts, ...}:
+    flake-parts.lib.mkFlake {inherit inputs
;} {
+      systems = import inputs.systems;
+      imports = [./nix];
+    };
+}
 

diff --git a/nix/default.nix b/nix/default.nix
new file mode 100644
index 0000000..96696e7
--- /dev/null
+++ b/nix/default.nix
@@ -0,0 +1,5 @@
+{
+  imports = [
+    ./shell.nix
+  ];
+}

diff --git a/nix/default.nix b/nix/default.n
ix
new file mode 100644
index 0000000..96696e7
--- /dev/null
+++ b/nix/default.nix
@@ -0,0 +1,5 @@
+{
+  imports = [
+    ./shell.nix
+  ];
+}
 

diff --git a/nix/lib/classConfigs.nix b/nix/lib/classConfigs.nix
new file mode 100644
index 0000000..1793685
--- /dev/null
+++ b/nix/lib/classConfigs.nix
@@ -0,0 +1,181 @@
+{
+  lib,
+  self,
+  ...
+}: let
+  raidBuffsLib = import ./raidBuffs.nix {inherit lib;};
+  raidDebuffsLib = import ./raidDebuffs.nix {inherit lib;};
+  encountersLib = import ./encounters.nix {inherit lib;};
+
+  # Base configuration that most specs will use
+  baseConfig = {
+    iterations = 12500;
+    randomSeed = "4260890857";
+    debugFirstIteration = true;
+    distanceFromTarget = 5;
+    reactionTimeMs = 100;
+    raidBuffs = raidBuffsLib.fullBuffs;
+    raidDebuffs = raidDebuffsLib.fullDebuffs;
+  };
+
+  # Melee base config
+  meleeConfig = baseConfig;
+
+  # Ranged base config
+  rangedConfig =
+    baseConfig
+    // {
+      distanceFromTarget = 25;
+    };
+
+  # Caster base config
+  casterConfig =
+    baseConfig
+    // {
+      distanceFromTarget = 25;
+    };
+
+  # Class-specific configurations
+  monk = {
+    windwalker = {
+      singleTarget =
+        meleeConfig
+        // {
+          class = "monk";
+          spec = "windwalker";
+          race = "orc";
+          gearset = "p1_bis_dw";
+          apl = "default";
+          consumables = {
+            prepotId = 76089;
+            potId = 76089;
+            flaskId = 76084;
+            foodId = 74648;
+          };
+          profession1 = "Engineering";
+          profession2 = "Tailoring";
+          talents = "213322";
+          glyphs = {
+            major1 = 85697;
+            major2 = 87900;
+            minor1 = 90715;
+          };
+          buffs = {};
+          debuffs = {};
+          targetDummies = 1;
+          options = {};
+        };
+
+      multiTarget =
+        monk.windwalker.singleTarget
+        // {
+          targetDummies = 9;
+        };
+
+      # Challenge Mode variants
+      challengeMode =
+        monk.windwalker.singleTarget
+        // {
+          challengeMode = true;
+        };
+
+      challengeModeMultiTarget =
+        monk.windwalker.singleTarget
+        // {
+          challengeMode = true;
+          targetDummies = 9;
+        };
+    };
+
+    brewmaster = {
+      singleTarget =
+        meleeConfig
+        // {
+          class = "monk";
+          spec = "brewmaster";
+          race = "Pandaren";
+          gearset = "p1_bis";
+          apl = "default";
+          consumables = {
+            prepotId = 76089;
+            potId = 76089;
+            flaskId = 76084;
+            foodId = 74648;
+          };
+          profession1 = "Engineering";
+          profession2 = "Tailoring";
+          talents = "213322";
+          glyphs = {
+            major1 = 85697;
+            major2 = 87900;
+            minor1 = 90715;
+          };
+          buffs = {};
+          debuffs = {};
+          targetDummies = 1;
+          options = {};
+        };
+
+      # Challenge Mode variant
+      challengeMode =
+        monk.brewmaster.singleTarget
+        // {
+          challengeMode = true;
+        };
+    };
+
+    mistweaver = {
+      singleTarget =
+        casterConfig
+        // {
+          class = "monk";
+          spec = "mistweaver";
+          race = "Pandaren";
+          gearset = "p1_bis";
+          apl = "default";
+          consumables = {
+            prepotId = 76089;
+            potId = 76089;
+            flaskId = 76084;
+            foodId = 74648;
+          };
+          profession1 = "Engineering";
+          profession2 = "Tailoring";
+          talents = "213322";
+          glyphs = {
+            major1 = 85697;
+            major2 = 87900;
+            minor1 = 90715;
+          };
+          buffs = {};
+          debuffs = {};
+          targetDummies = 1;
+          options = {};
+        };
+
+      # Challenge Mode variant
+      challengeMode =
+        monk.mistweaver.singleTarget
+        // {
+          challengeMode = true;
+        };
+    };
+  };
+
+  # Generate simulation function
+  generateSimulation = classConfig: encounterType: let
+    generateInfile = import ./generateInfile.nix {inherit lib self;};
+    encounter = encounterType;
+  in
+    generateInfile (classConfig // {inherit encounter;});
+in {
+  inherit baseConfig meleeConfig rangedConfig casterConfig monk generateSimulatio
n;
+
+  # Export encounters for easy access
+  encounters = encountersLib;
+
+  # Export buff/debuff libs for customization
+  raidBuffs = raidBuffsLib;
+  raidDebuffs = raidDebuffsLib;
+}
+

diff --git a/nix/lib/classConfigs.nix b/nix/
lib/classConfigs.nix
new file mode 100644
index 0000000..1793685
--- /dev/null
+++ b/nix/lib/classConfigs.nix
@@ -0,0 +1,181 @@
+{
+  lib,
+  self,
+  ...
+}: let
+  raidBuffsLib = import ./raidBuffs.nix {in
herit lib;};
+  raidDebuffsLib = import ./raidDebuffs.nix
 {inherit lib;};
+  encountersLib = import ./encounters.nix {
inherit lib;};
+
+  # Base configuration that most specs will
 use
+  baseConfig = {
+    iterations = 12500;
+    randomSeed = "4260890857";
+    debugFirstIteration = true;
+    distanceFromTarget = 5;
+    reactionTimeMs = 100;
+    raidBuffs = raidBuffsLib.fullBuffs;
+    raidDebuffs = raidDebuffsLib.fullDebuff
s;
+  };
+
+  # Melee base config
+  meleeConfig = baseConfig;
+
+  # Ranged base config
+  rangedConfig =
+    baseConfig
+    // {
+      distanceFromTarget = 25;
+    };
+
+  # Caster base config
+  casterConfig =
+    baseConfig
+    // {
+      distanceFromTarget = 25;
+    };
+
+  # Class-specific configurations
+  monk = {
+    windwalker = {
+      singleTarget =
+        meleeConfig
+        // {
+          class = "monk";
+          spec = "windwalker";
+          race = "orc";
+          gearset = "p1_bis_dw";
+          apl = "default";
+          consumables = {
+            prepotId = 76089;
+            potId = 76089;
+            flaskId = 76084;
+            foodId = 74648;
+          };
+          profession1 = "Engineering";
+          profession2 = "Tailoring";
+          talents = "213322";
+          glyphs = {
+            major1 = 85697;
+            major2 = 87900;
+            minor1 = 90715;
+          };
+          buffs = {};
+          debuffs = {};
+          targetDummies = 1;
+          options = {};
+        };
+
+      multiTarget =
+        monk.windwalker.singleTarget
+        // {
+          targetDummies = 9;
+        };
+
+      # Challenge Mode variants
+      challengeMode =
+        monk.windwalker.singleTarget
+        // {
+          challengeMode = true;
+        };
+
+      challengeModeMultiTarget =
+        monk.windwalker.singleTarget
+        // {
+          challengeMode = true;
+          targetDummies = 9;
+        };
+    };
+
+    brewmaster = {
+      singleTarget =
+        meleeConfig
+        // {
+          class = "monk";
+          spec = "brewmaster";
+          race = "Pandaren";
+          gearset = "p1_bis";
+          apl = "default";
+          consumables = {
+            prepotId = 76089;
+            potId = 76089;
+            flaskId = 76084;
+            foodId = 74648;
+          };
+          profession1 = "Engineering";
+          profession2 = "Tailoring";
+          talents = "213322";
+          glyphs = {
+            major1 = 85697;
+            major2 = 87900;
+            minor1 = 90715;
+          };
+          buffs = {};
+          debuffs = {};
+          targetDummies = 1;
+          options = {};
+        };
+
+      # Challenge Mode variant
+      challengeMode =
+        monk.brewmaster.singleTarget
+        // {
+          challengeMode = true;
+        };
+    };
+
+    mistweaver = {
+      singleTarget =
+        casterConfig
+        // {
+          class = "monk";
+          spec = "mistweaver";
+          race = "Pandaren";
+          gearset = "p1_bis";
+          apl = "default";
+          consumables = {
+            prepotId = 76089;
+            potId = 76089;
+            flaskId = 76084;
+            foodId = 74648;
+          };
+          profession1 = "Engineering";
+          profession2 = "Tailoring";
+          talents = "213322";
+          glyphs = {
+            major1 = 85697;
+            major2 = 87900;
+            minor1 = 90715;
+          };
+          buffs = {};
+          debuffs = {};
+          targetDummies = 1;
+          options = {};
+        };
+
+      # Challenge Mode variant
+      challengeMode =
+        monk.mistweaver.singleTarget
+        // {
+          challengeMode = true;
+        };
+    };
+  };
+
+  # Generate simulation function
+  generateSimulation = classConfig: encount
erType: let
+    generateInfile = import ./generateInfil
e.nix {inherit lib self;};
+    encounter = encounterType;
+  in
+    generateInfile (classConfig // {inherit
 encounter;});
+in {
+  inherit baseConfig meleeConfig rangedConf
ig casterConfig monk generateSimulation;
+
+  # Export encounters for easy access
+  encounters = encountersLib;
+
+  # Export buff/debuff libs for customizati
on
+  raidBuffs = raidBuffsLib;
+  raidDebuffs = raidDebuffsLib;
+}
+
 

diff --git a/nix/lib/encounters.nix b/nix/lib/encounters.nix
new file mode 100644
index 0000000..33128fa
--- /dev/null
+++ b/nix/lib/encounters.nix
@@ -0,0 +1,53 @@
+{lib, ...}: let
+  # Base encounter template
+  inherit (lib) genList;
+  mobs = import ./targets.nix;
+  mkEncounter = {
+    duration ? 300,
+    durationVariation ? 60,
+    targets ? [],
+  }: {
+    apiVersion = 1;
+    inherit duration durationVariation targets;
+
+    # default execute config
+    executeProportion20 = 0.2;
+    executeProportion25 = 0.25;
+    executeProportion35 = 0.35;
+    executeProportion45 = 0.45;
+    executeProportion90 = 0.9;
+  };
+
+  # Duration-based encounter templates
+  raid = {
+    long = {
+      singleTarget = mkEncounter {
+        targets = [
+          mobs.defaultRaidBoss
+        ];
+      };
+
+      twoTarget = mkEncounter {
+        targets = genList (_: mobs.defaultRaidBoss) 3;
+      };
+
+      threeTarget = mkEncounter {
+        targets = genList (_: mobs.defaultRaidBoss) 3;
+      };
+
+      fiveTarget = mkEncounter {
+        targets = genList (_: mobs.defaultRaidBoss) 10;
+      };
+
+      tenTarget = mkEncounter {
+        targets = genList (_: mobs.defaultRaidBoss) 10;
+      };
+
+      twentyTarget = mkEncounter {
+        targets = genList (_: mobs.defaultRaidBoss) 20;
+      };
+    };
+  };
+in
+  raid
+

diff --git a/nix/lib/encounters.nix b/nix/li
b/encounters.nix
new file mode 100644
index 0000000..33128fa
--- /dev/null
+++ b/nix/lib/encounters.nix
@@ -0,0 +1,53 @@
+{lib, ...}: let
+  # Base encounter template
+  inherit (lib) genList;
+  mobs = import ./targets.nix;
+  mkEncounter = {
+    duration ? 300,
+    durationVariation ? 60,
+    targets ? [],
+  }: {
+    apiVersion = 1;
+    inherit duration durationVariation targ
ets;
+
+    # default execute config
+    executeProportion20 = 0.2;
+    executeProportion25 = 0.25;
+    executeProportion35 = 0.35;
+    executeProportion45 = 0.45;
+    executeProportion90 = 0.9;
+  };
+
+  # Duration-based encounter templates
+  raid = {
+    long = {
+      singleTarget = mkEncounter {
+        targets = [
+          mobs.defaultRaidBoss
+        ];
+      };
+
+      twoTarget = mkEncounter {
+        targets = genList (_: mobs.defaultR
aidBoss) 3;
+      };
+
+      threeTarget = mkEncounter {
+        targets = genList (_: mobs.defaultR
aidBoss) 3;
+      };
+
+      fiveTarget = mkEncounter {
+        targets = genList (_: mobs.defaultR
aidBoss) 10;
+      };
+
+      tenTarget = mkEncounter {
+        targets = genList (_: mobs.defaultR
aidBoss) 10;
+      };
+
+      twentyTarget = mkEncounter {
+        targets = genList (_: mobs.defaultR
aidBoss) 20;
+      };
+    };
+  };
+in
+  raid
+
 

diff --git a/nix/lib/generateInfile.nix b/nix/lib/generateInfile.nix
new file mode 100644
index 0000000..fb0b1a9
--- /dev/null
+++ b/nix/lib/generateInfile.nix
@@ -0,0 +1,104 @@
+{
+  lib,
+  self,
+  ...
+}: let
+  inherit (lib.strings) toSentenceCase;
+  
+  # Import utility modules
+  raidBuffsLib = import ./raidBuffs.nix {inherit lib;};
+  raidDebuffsLib = import ./raidDebuffs.nix {inherit lib;};
+  encountersLib = import ./encounters.nix {inherit lib;};
+  generateInfile = {
+    class,
+    spec,
+    race,
+    gearset,
+    consumables,
+    profession1,
+    profession2,
+    talents,
+    buffs ? {},
+    debuffs,
+    apl,
+    targetDummies ? 1,
+    distanceFromTarget ? 5,
+    numberOfTargets ? 1,
+    iterations ? 12500,
+    options ? {},
+    glyphs,
+    raidBuffs ? raidBuffsLib.fullBuffs,
+    raidDebuffs ? raidDebuffsLib.fullDebuffs,
+    reactionTimeMs ? 100,
+    encounter ? encountersLib.long.singleTarget,
+    randomSeed ? "4260890857",
+    debugFirstIteration ? true,
+    challengeMode ? false,
+  }: let
+    baseEquipment = builtins.fromJSON (builtins.readFile "${self}/ui/${class}/${s
pec}/gear_sets/${gearset}.gear.json");
+    rotation = builtins.fromJSON (builtins.readFile "${self}/ui/${class}/${spec}/
apls/${apl}.apl.json");
+    
+    # Add challengeMode flag to all equipment items if enabled
+    equipment = if challengeMode then
+      baseEquipment // {
+        items = map (item: item // {challengeMode = true;}) baseEquipment.items;
+      }
+    else
+      baseEquipment;
+  in
+    builtins.toJSON {
+      requestId = "raidSimAsync-62a8c84a7df3627";
+      raid = {
+        parties = [
+          {
+            players = [
+              {
+                name = "Player";
+                race = "Race${toSentenceCase race}";
+                class = "Class${toSentenceCase class}";
+                inherit equipment consumables buffs glyphs profession1 profession
2 rotation reactionTimeMs distanceFromTarget;
+                talentsString = talents;
+                cooldowns = {};
+                healingModel = {};
+                # Add spec-specific options
+                "${spec}${toSentenceCase class}" = {
+                  inherit options;
+                };
+              }
+              {}
+              {}
+              {}
+              {}
+            ];
+            buffs = {};
+          }
+          {
+            players = [{} {} {} {} {}];
+            buffs = {};
+          }
+          {
+            players = [{} {} {} {} {}];
+            buffs = {};
+          }
+          {
+            players = [{} {} {} {} {}];
+            buffs = {};
+          }
+          {
+            players = [{} {} {} {} {}];
+            buffs = {};
+          }
+        ];
+        numActiveParties = 5;
+        buffs = raidBuffs;
+        debuffs = raidDebuffs;
+        inherit targetDummies;
+      };
+      inherit encounter;
+      simOptions = {
+        inherit iterations randomSeed debugFirstIteration;
+      };
+      type = "SimTypeIndividual";
+    };
+in
+  generateInfile

diff --git a/nix/lib/generateInfile.nix b/ni
x/lib/generateInfile.nix
new file mode 100644
index 0000000..fb0b1a9
--- /dev/null
+++ b/nix/lib/generateInfile.nix
@@ -0,0 +1,104 @@
+{
+  lib,
+  self,
+  ...
+}: let
+  inherit (lib.strings) toSentenceCase;
+  
+  # Import utility modules
+  raidBuffsLib = import ./raidBuffs.nix {in
herit lib;};
+  raidDebuffsLib = import ./raidDebuffs.nix
 {inherit lib;};
+  encountersLib = import ./encounters.nix {
inherit lib;};
+  generateInfile = {
+    class,
+    spec,
+    race,
+    gearset,
+    consumables,
+    profession1,
+    profession2,
+    talents,
+    buffs ? {},
+    debuffs,
+    apl,
+    targetDummies ? 1,
+    distanceFromTarget ? 5,
+    numberOfTargets ? 1,
+    iterations ? 12500,
+    options ? {},
+    glyphs,
+    raidBuffs ? raidBuffsLib.fullBuffs,
+    raidDebuffs ? raidDebuffsLib.fullDebuff
s,
+    reactionTimeMs ? 100,
+    encounter ? encountersLib.long.singleTa
rget,
+    randomSeed ? "4260890857",
+    debugFirstIteration ? true,
+    challengeMode ? false,
+  }: let
+    baseEquipment = builtins.fromJSON (buil
tins.readFile "${self}/ui/${class}/${spec}/g
ear_sets/${gearset}.gear.json");
+    rotation = builtins.fromJSON (builtins.
readFile "${self}/ui/${class}/${spec}/apls/$
{apl}.apl.json");
+    
+    # Add challengeMode flag to all equipme
nt items if enabled
+    equipment = if challengeMode then
+      baseEquipment // {
+        items = map (item: item // {challen
geMode = true;}) baseEquipment.items;
+      }
+    else
+      baseEquipment;
+  in
+    builtins.toJSON {
+      requestId = "raidSimAsync-62a8c84a7df
3627";
+      raid = {
+        parties = [
+          {
+            players = [
+              {
+                name = "Player";
+                race = "Race${toSentenceCas
e race}";
+                class = "Class${toSentenceC
ase class}";
+                inherit equipment consumabl
es buffs glyphs profession1 profession2 rota
tion reactionTimeMs distanceFromTarget;
+                talentsString = talents;
+                cooldowns = {};
+                healingModel = {};
+                # Add spec-specific options
+                "${spec}${toSentenceCase cl
ass}" = {
+                  inherit options;
+                };
+              }
+              {}
+              {}
+              {}
+              {}
+            ];
+            buffs = {};
+          }
+          {
+            players = [{} {} {} {} {}];
+            buffs = {};
+          }
+          {
+            players = [{} {} {} {} {}];
+            buffs = {};
+          }
+          {
+            players = [{} {} {} {} {}];
+            buffs = {};
+          }
+          {
+            players = [{} {} {} {} {}];
+            buffs = {};
+          }
+        ];
+        numActiveParties = 5;
+        buffs = raidBuffs;
+        debuffs = raidDebuffs;
+        inherit targetDummies;
+      };
+      inherit encounter;
+      simOptions = {
+        inherit iterations randomSeed debug
FirstIteration;
+      };
+      type = "SimTypeIndividual";
+    };
+in
+  generateInfile
 

diff --git a/nix/lib/raidBuffs.nix b/nix/lib/raidBuffs.nix
new file mode 100644
index 0000000..cf9b940
--- /dev/null
+++ b/nix/lib/raidBuffs.nix
@@ -0,0 +1,40 @@
+{lib, ...}: let
+  # Full raid buff configuration - all buffs enabled
+  fullBuffs = {
+    trueshotAura = true;
+    unholyAura = true;
+    darkIntent = true;
+    moonkinAura = true;
+    leaderOfThePack = true;
+    blessingOfMight = true;
+    legacyOfTheEmperor = true;
+    bloodlust = true;
+    stormlashTotemCount = 5;
+    skullBannerCount = 3;
+  };
+
+  # Full buffs without bloodlust/heroism
+  fullBuffsNoLust = fullBuffs // {
+    bloodlust = false;
+  };
+
+  # No raid buffs
+  noBuffs = {
+    trueshotAura = false;
+    unholyAura = false;
+    darkIntent = false;
+    moonkinAura = false;
+    leaderOfThePack = false;
+    blessingOfMight = false;
+    legacyOfTheEmperor = false;
+    bloodlust = false;
+    stormlashTotemCount = 0;
+    skullBannerCount = 0;
+  };
+
+  # Function to merge custom buffs with defaults
+  mergeRaidBuffs = customBuffs: fullBuffs // customBuffs;
+
+in {
+  inherit fullBuffs fullBuffsNoLust noBuffs mergeRaidBuffs;
+}
\ No newline at end of file

diff --git a/nix/lib/raidBuffs.nix b/nix/lib
/raidBuffs.nix
new file mode 100644
index 0000000..cf9b940
--- /dev/null
+++ b/nix/lib/raidBuffs.nix
@@ -0,0 +1,40 @@
+{lib, ...}: let
+  # Full raid buff configuration - all buff
s enabled
+  fullBuffs = {
+    trueshotAura = true;
+    unholyAura = true;
+    darkIntent = true;
+    moonkinAura = true;
+    leaderOfThePack = true;
+    blessingOfMight = true;
+    legacyOfTheEmperor = true;
+    bloodlust = true;
+    stormlashTotemCount = 5;
+    skullBannerCount = 3;
+  };
+
+  # Full buffs without bloodlust/heroism
+  fullBuffsNoLust = fullBuffs // {
+    bloodlust = false;
+  };
+
+  # No raid buffs
+  noBuffs = {
+    trueshotAura = false;
+    unholyAura = false;
+    darkIntent = false;
+    moonkinAura = false;
+    leaderOfThePack = false;
+    blessingOfMight = false;
+    legacyOfTheEmperor = false;
+    bloodlust = false;
+    stormlashTotemCount = 0;
+    skullBannerCount = 0;
+  };
+
+  # Function to merge custom buffs with def
aults
+  mergeRaidBuffs = customBuffs: fullBuffs /
/ customBuffs;
+
+in {
+  inherit fullBuffs fullBuffsNoLust noBuffs
 mergeRaidBuffs;
+}
\ No newline at end of file
 

diff --git a/nix/lib/raidDebuffs.nix b/nix/lib/raidDebuffs.nix
new file mode 100644
index 0000000..cbb74a8
--- /dev/null
+++ b/nix/lib/raidDebuffs.nix
@@ -0,0 +1,19 @@
+{lib, ...}: let
+  # Full raid debuff configuration - all debuffs enabled
+  fullDebuffs = {
+    physicalVulnerability = true;
+    weakenedArmor = true;
+  };
+
+  # No raid debuffs
+  noDebuffs = {
+    physicalVulnerability = false;
+    weakenedArmor = false;
+  };
+
+  # Function to merge custom debuffs with defaults
+  mergeRaidDebuffs = customDebuffs: fullDebuffs // customDebuffs;
+
+in {
+  inherit fullDebuffs noDebuffs mergeRaidDebuffs;
+}
\ No newline at end of file

diff --git a/nix/lib/raidDebuffs.nix b/nix/l
ib/raidDebuffs.nix
new file mode 100644
index 0000000..cbb74a8
--- /dev/null
+++ b/nix/lib/raidDebuffs.nix
@@ -0,0 +1,19 @@
+{lib, ...}: let
+  # Full raid debuff configuration - all de
buffs enabled
+  fullDebuffs = {
+    physicalVulnerability = true;
+    weakenedArmor = true;
+  };
+
+  # No raid debuffs
+  noDebuffs = {
+    physicalVulnerability = false;
+    weakenedArmor = false;
+  };
+
+  # Function to merge custom debuffs with d
efaults
+  mergeRaidDebuffs = customDebuffs: fullDeb
uffs // customDebuffs;
+
+in {
+  inherit fullDebuffs noDebuffs mergeRaidDe
buffs;
+}
\ No newline at end of file
 

diff --git a/nix/lib/targets.nix b/nix/lib/targets.nix
new file mode 100644
index 0000000..d3c2d5c
--- /dev/null
+++ b/nix/lib/targets.nix
@@ -0,0 +1,27 @@
+{lib, ...}: let
+  mkTarget = {
+    id ? 31146,
+    name ? "Raid Target",
+    level ? 93,
+    type ? "mechanical",
+    minBaseDamage ? 550000,
+    damageSpread ? 0.4,
+    swingSpeed ? 2,
+  }: {
+    inherit id name level damageSpread swingSpeed minBaseDamage;
+    mobType = "MobType${lib.string.toSentenceCase type}";
+  };
+  mobs = {
+    defaultRaidBoss = mkTarget {};
+    smallTrash = mkTarget {
+      level = 90;
+      minBaseDamage = 15000;
+    };
+    largeTrash = mkTarget {
+      level = 90;
+      minBaseDamage = 40000;
+    };
+    # todo add raid bosses
+  };
+in
+  targets

diff --git a/nix/lib/targets.nix b/nix/lib/t
argets.nix
new file mode 100644
index 0000000..d3c2d5c
--- /dev/null
+++ b/nix/lib/targets.nix
@@ -0,0 +1,27 @@
+{lib, ...}: let
+  mkTarget = {
+    id ? 31146,
+    name ? "Raid Target",
+    level ? 93,
+    type ? "mechanical",
+    minBaseDamage ? 550000,
+    damageSpread ? 0.4,
+    swingSpeed ? 2,
+  }: {
+    inherit id name level damageSpread swin
gSpeed minBaseDamage;
+    mobType = "MobType${lib.string.toSenten
ceCase type}";
+  };
+  mobs = {
+    defaultRaidBoss = mkTarget {};
+    smallTrash = mkTarget {
+      level = 90;
+      minBaseDamage = 15000;
+    };
+    largeTrash = mkTarget {
+      level = 90;
+      minBaseDamage = 40000;
+    };
+    # todo add raid bosses
+  };
+in
+  targets
 

diff --git a/nix/pkgs/pkgs.nix b/nix/pkgs/pkgs.nix
new file mode 100644
index 0000000..7300efe
--- /dev/null
+++ b/nix/pkgs/pkgs.nix
@@ -0,0 +1,24 @@
+{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
new file mode 100644
index 0000000..7300efe
--- /dev/null
+++ b/nix/pkgs/pkgs.nix
@@ -0,0 +1,24 @@
+{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
new file mode 100644
index 0000000..48a557f
--- /dev/null
+++ b/nix/pkgs/rankings.nix
@@ -0,0 +1,106 @@
+{
+  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
new file mode 100644
index 0000000..48a557f
--- /dev/null
+++ b/nix/pkgs/rankings.nix
@@ -0,0 +1,106 @@
+{
+  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/shell.nix b/nix/shell.nix
new file mode 100644
index 0000000..3ff0e50
--- /dev/null
+++ b/nix/shell.nix
@@ -0,0 +1,17 @@
+{
+  perSystem = {
+    pkgs,
+    inputs',
+    ...
+  }: {
+    devShells.default = pkgs.mkShellNoCC {
+      name = "project devshell";
+      packages = builtins.attrValues {
+        inherit
+          (inputs'.wowsims.packages)
+          wowsimcli
+          ;
+      };
+    };
+  };
+}

diff --git a/nix/shell.nix b/nix/shell.nix
new file mode 100644
index 0000000..3ff0e50
--- /dev/null
+++ b/nix/shell.nix
@@ -0,0 +1,17 @@
+{
+  perSystem = {
+    pkgs,
+    inputs',
+    ...
+  }: {
+    devShells.default = pkgs.mkShellNoCC {
+      name = "project devshell";
+      packages = builtins.attrValues {
+        inherit
+          (inputs'.wowsims.packages)
+          wowsimcli
+          ;
+      };
+    };
+  };
+}
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET