
Security News
Scaling Socket from Zero to 10,000+ Organizations
Socket CEO Feross Aboukhadijeh shares lessons from scaling a developer security startup to 10,000+ organizations in this founder interview.
pyoe2-craftpath
Advanced tools
A tool for Path of Exile 2 to find the best craftpaths based on the categories: *most likely, most efficient and cheapest*, between a starting item and a target item.
A tool for Path of Exile 2 to find the best craftpaths based on the categories: most likely, most efficient and cheapest, between a starting item and a target item.
Available as Python package pyoe2-craftpath or as "bro just gimme something that goes brrr"-executable command-line utility for Windows under Releases. Bindings for Python are generated with PyO3, to let you build your own data analysis pipeline upon the calculated items and craftpaths. Made possible by the power of 🦀 Rust.
Built and tested for Path of Exile 2 on version 0.3.1. Supported Python versions and platforms are determined by the automated pipeline, here (should support all widely used platforms and versions >=3.10).
The primary goal is to provide a framework for calculating craft paths and to enable its integration into native applications (over FFI), including overlays or mobile apps ... or just run easily as a Windows executable or Python library.
To keep it short, I was introduced to Path of Exile 2 and enjoyed it quite a bit. After reaching higher levels and starting to get the hang of things, I became interested in crafting. As big noob, I was completly overwhelmed with the information available.
Me need simple. Me want good item. How get good item?
CraftPath. The purpose of this tool is give it information about your current item and the affixes you want it to have, then let it efficiently calculate possible craftpaths; Without the need to manually look up mod weights, mod groups, or spend hours crunching probabilities on a Casio calculator, as all true PoE gamers do1. It simulates all sensible currency sequences that can be applied on a starting item, and collects the best routes that lead to the given target item, based on the specified statistic (more in Development Strategy and Caveats).
Keep in mind that this project is in its early stages, and can contain bugs and lack features. Therefore, the section Features should give an overview over all planned/completed/unplanned currencies and known bugs. If your topic is not documented there, it is yet unknown and not reviewed. Feel free to create an Issue with more information!
My plan is of course to reach version 1.0.0 ... which depends on the traction this project gains, which in turn affects how much free time I'm motivated to dedicate to it, which in turn leads to a more robust and well-rounded project. Until then, this notice lingers... possibly forever. 🧙‍♂️
| Currency | Options | Status | Note |
|---|---|---|---|
| Orb of Transmutation | Normal, Greater (55), Perfect (70) | Completed | |
| Orb of Augmentation | Normal, Greater (55), Perfect (70) | Completed | |
| Regal Orb | Normal, Greater (35), Perfect (50), Homogenising Coronation | Completed | |
| Orb of Alchemy | Not Planned | Too random to craft deterministically. | |
| Chaos Orb | Normal, Greater (35), Perfect (50), Dex/Sin Erasure, *Whittling | Completed | Whittling removes the affix based on minimal item level, not tier. |
| Exalted Orb | Normal, Greater (35), Perfect (50), Dex/Sin Exaltation, Homogenising Exaltation | Completed | |
| Orb of Annulment | Dex/Sin Annulment | Completed | |
| Divine Orb | Not Planned | Different use-case. | |
| Artificers Orb | Completed | Click item. Socket. Much wow. Such awesome. | |
| Fracturing Orb | Partially Completed, Planned | Algorithm respects fractured affixes if present on the start item; does not create fractured affixes automatically yet. | |
| Vaal Orb | Omen of Corruption | Partially Completed, Partially Planned | Effect 1/3. Creates new socket and corrupts item. Effect 2/3. Does not create implicits yet, but is MAYBE planned (low prio). Effect 3/3. Reroll up to three modifiers is NOT planned. |
| Lesser to Greater Essence | Completed | ||
| Perfect Essence | Dex/Sin Crystallisation | Completed | Algorithm tries to create a temporary affix to swap with, if otherwise unreachable. |
| Desecration | Abyssal Echoes, Blackhooded, Liege, Sovereign, Sin/Dex Necromancy | Partially Completed, Not Planned | "Blackhooded, Liege, Sovereign" are forced. Loose propagation of affixes is not planned. ATTENTION Desecration weights are unknown and are treated equally by the algorithm; all desecration weights = 1. |
| Others | On request | If not explicitly listed in this table, other crafting methods have not been reviewed yet or are not planned. Open an issue if I forgot something that you would find nice to have. |
All affix weights are fetched from craftofexile.com; refer to the given link for infos about how the weights are collected.
This tool is primarily intended to be used as a framework for native applications, such as overlays or mobile apps (via FFI). If you need help creating an FFI from this tool to your programming language, feel free to create an Issue with your target.
Another way to easily run the tool is as a Python library, which also demonstrates one way to use FFI. Check out the extended Python example as a Jupyter Notebook or browse the python_examples directory for commented usage examples in Python.
The following section shows a guide for the quick-n-dirty approach to run the Windows executable via the console, since I wanted to offer a simple(r) solution for those who just want to have a basic overview and are not planning to create further analytical pipelines.
First things first. Download the program from Releases.
To make the CLI more approachable, I've uploaded a video demonstrating the workflow, from configuring the executable to supplying items for calculation. You can watch it on YouTube by clicking the thumbnail, or here:
pyoe2-craftpath.exe [options]
Available optional, options:
--start_item_path <Path to JSON File>Default: pyoe2-craftpath/startitem.json
Provides the file location of the saved item to treat as the starting item of the craft.
Use CraftOfExile → Emulator → Export and paste the output into pyoe2-craftpath/startitem.json.
--target_item_path <Path to JSON File>Default: pyoe2-craftpath/targetitem.json
Provides the file location of the saved item to treat as the end item of the craft.
Use CraftOfExile → Emulator → Export and paste the output into pyoe2-craftpath/targetitem.json.
--cache_path <Path to Temp Folder>Default: pyoe2-craftpath
Used for caching CraftOfExile's and
PoE.Ninja's datasets.
The folder must already exist.
Mostly to express consent for the program to cache things and edit that folder’s contents.
--poe2_league <League>Default: Rise of the Abyssal
Fetches PoE.Ninja's economy data for the specified league.
--amount_routes <Number>Default: 5
Number of craft paths collected and printed per stats category.
(Current categories: highest chance, most efficient, cheapest → 3 × amount_routes shown.)
--no_updatesDefault: checks GitHub for updates
If set, CraftPath will not query GitHub or check for newer versions.
--no_groupsDefault: collects all possible paths
If set, CraftPath will not collect all possible path groups.
This greatly reduces RAM usage but results in less complete output.
--max-ram <<Number>[GB|KB|MB]>Default: 1GB
Sets the maximum amount of RAM the program may use during path collection.
The following section explains the inner workings of my algorithm, if you are interested in contributing or just want to have an idea of how this tool works. If you're only here for the crafting you can skip this.
The architecture to return the best paths based on custom statistics consists of two important parts. Firstly, the MatrixPropagator and secondly the StatisticAnalyzer(s).
MatrixBuilder. This structure is efficiently constructed as a tree. For an actual implementation refer to HappyPathMatrixBuilderImpl.To constraint propagation and massivly reduce complexity, my algorithm tries to stay on the Happy Path as much as possible. That means, that affixes that can be rolled, but are not included in the desired affix state, will not be considered for additive currencies like Exalted Orb. Subtractive currencies like Orb of Annulment will only result in affix states, that lose unwanted affixes. (= Definition of all sensible) Simply put, if my algorithm was a player, it would immediatly stop crafting an item, that does not gain an affix from the desired affixes (or lose an unwanted affix).
While this approach enables more efficient path construction, it may miss routes that can only be reached by temporarily applying an undesired affix. Such an edge case can be found by trying to apply Perfect Essence.
Let's assume we have an item with three desirable prefixes that we want to keep, and we plan to apply a
Perfect Essenceto add a suffix. Naivly applying it results in an item with two prefixes and the new suffix from thePerfect Essence. This action is not done by HappyPathMatrixBuilderImpl, since it would remove a wanted affix. Thus, propagation stops and completes without finding a craft path that leads to the target item at all.
To fix this specific edge case, PerfectEssencePropagator introduces an additional temporary step, forcing propagation outside of the Happy Path: expanding on the mentioned example, it first applies a suffix from the unwanted affix pool. This ensures that the three desired prefixes remain untouched, while the temporary suffix can be replaced with the Perfect Essence and the Dextral Crystallisation omen.
I'm sure many more such edge cases exist, and those need to be specifically implemented. If you can think of any, please tell me :3
I haven't implemented anything crazy for this one, so I'll keep it short.
The most interesting detail is probably the need to filter out theoretical cyclic propagations. I'm not aware of this happening in my algorithm, but it is an edge-case that must be handled to avoid infinite loops. A theoretical possibility would be f. e. Exalted Orb, Orb of Annulment, Exalted Orb, Orb of Annulment ... resulting in the same affix state. Therefore calculate_crafting_paths only continues paths, that do not contain the same affix state twice2. What would be nice as well, is an improved filtration of senseless routes ... but the definition for senseless routes is actually the hard task here. Cauz the above example only filters out the same affixes. It would still calculate the same currency sequence for different affixes, which is senseless, but I do not know how to filter it out efficiently yet. Hence, the current version only filters out cycles, and lets the StatisticalAnalyzers handle the sorting. Since the senseless routes will have a much worse weight than the best ones, they will be filtered out naturally; on the expense of checking senseless routes, which really is a problem on deep paths (6 affixes+), resulting in millions of senseless checks.
I've published the project on crates.io (and PyPI). You can either use the API to build your own extension as own Rust crate depending on pyoe2-craftpath. If you're planning to offer FFI for your language, free to open an Issue to ask about technical stuff.
If you want, you can also create a pull request to have it directly included here. The only requirement is the usage of the Conventional Commits format for your commit messages and preferably a new test for your code.
I recommend looking at the central types StatisticAnalyzerCurrencyGroupPreset, StatisticAnalyzerPathPreset and MatrixBuilderPreset which are most likely the things that an extension wants to offer. The mentioned enums provide specific, usuable implementations for both Rust and Python and integrate seamlessly into the rest of CraftPath's "ecosystem". E. g. a DynMatrixBuilder could be passed over arguments in Section 5 of the Jupyter Notebook example. This is possible for statistic analyzers as well (refer to Section 6).
Of course, Grinding Gear Games for providing Path of Exile 2, that got me hooked to the extent of actually coding this.
CraftOfExile that permitted me to use their item data. CraftPath would not be possible without it. CoE offers an extensive, crunched mapping for weights, items, affixes, etc. Moreover I integrated CoE's Emulator Export outputs to parse the starting/target item, offering an external, easy capture of item information over a GUI. Since I as noob needed something hands-on, easy to use, CraftOfExile was essential for this project.
poe.ninja for providing a public API to fetch up-to-date currency exchange prices. Used by CraftPath to calculate the cost of a crafting path, and subsequently corresponding cost-based analysis. Cudos for hosting and keeping a free, public API alive for such a long time!
CraftPath is not affiliated with or endorsed by Grinding Gear Games
Source: trust me, bro ↩
Actually item state (ItemSnapshot), but in the given example w/e. The item state contains more information like rarity, base item id, level, etc. ↩
FAQs
A tool for Path of Exile 2 to find the best craftpaths based on the categories: *most likely, most efficient and cheapest*, between a starting item and a target item.
We found that pyoe2-craftpath demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket CEO Feross Aboukhadijeh shares lessons from scaling a developer security startup to 10,000+ organizations in this founder interview.

Research
Socket Threat Research maps a rare inside look at OtterCookie’s npm-Vercel-GitHub chain, adding 197 malicious packages and evidence of North Korean operators.

Research
Socket researchers identified a malicious Chrome extension that manipulates Raydium swaps to inject an undisclosed SOL transfer, quietly routing fees to an attacker wallet.