Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when reading, editing, or generating a Bethesda Game Studio load-order file (plugins.txt / loadorder.txt) for Fallout 4, Skyrim SE/AE/VR, Fallout 76, Starfield, or when launching xEdit with a custom plugin list. Authoritative reference for the asterisk-prefix format, official masters detection, ESL handling, and the routing rules between plugins.txt editing and xEdit daemon commands.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 252% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 312% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 233% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 400% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 289% | 0% |
> Harness status (2026-07-29): The local prototype harness was destroyed by an unattributed operation and will not be rebuilt. The historical .artifacts/mo2 example below is DEFUNCT. Testing now uses externally-configured Starfield or Fallout 4 MO2 instances; machine-specific details and the forensic record are private.
> Sources for every claim in this skill: Ortham/libloadorder (the library > behind LOOT), ModOrganizer2/modorganizer/src/profile.cpp, > ModOrganizer2/modorganizer-basic_games/.../game_plugins.py, and xEdit's > official docs Section 2.8.1.
| Format | Games | File | Activation marker | |---|---|---|---| | Asterisk format (modern) | Fallout 4, Skyrim SE/AE/VR, Fallout 4 VR, Starfield | plugins.txt | leading * = active | | Textfile-only (legacy) | Skyrim LE, Oblivion, Fallout 3, Fallout NV | plugins.txt (active only) + sibling loadorder.txt (full order) | presence in plugins.txt = active |
This skill covers the asterisk format in depth. If your target is Skyrim LE / Oblivion / FO3 / FNV, the rules are different — see the "Legacy format" section at the bottom.
| Context | Path | |---|---| | Vanilla install (no MO2) | %LOCALAPPDATA%\<GameFolder>\plugins.txt (e.g. Fallout4, Skyrim Special Edition, Starfield) | | MO2-managed | <MO2_Root>\profiles\<ProfileName>\plugins.txt | | MO2-managed sibling | <MO2_Root>\profiles\<ProfileName>\loadorder.txt (full order including inactive; MO2 keeps both) | | Agent-authored (experiments) | an agent-owned artifacts path — generate your own, pass to xedit_start({ pluginsFile }) |
Ownership in MO2 use: MO2 writes plugins.txt whenever the user toggles plugin checkboxes in the GUI. LOOT can also write it. If you mutate it under MO2, do it while MO2 is closed OR via mobase's IPluginList API — live edits while MO2 is open get overwritten on its next save.
# This file was automatically generated by Mod Organizer.
*Unofficial Fallout 4 Patch.esp ← * = ACTIVE; loads first among non-vanilla
ArmorKeywords.esm ← no * = present-but-INACTIVE; position preserved
*HUDFramework.esm
SomeDisabledMod.esp
*MyMod.esp ← bottom = loads LAST = wins conflictsVerbatim parser rules (from libloadorder/src/load_order/asterisk_based.rs):
# (column 0) → comment, ignored.* → plugin name follows; active.# must be at column 0.activated until renamed.
(libloadorder's default).
conflicts.
Ordering is not list housekeeping. It decides which plugin record or archive payload the game actually sees when two mods touch the same thing: later wins. For loose files, remember the separate asset layer: loose files can win over BA2/BSA archive contents even when their plugin loads earlier. Use ordering to choose whole-record / whole-archive winners; use a patch when you need one final record stitched from multiple mods.
Iron law: if the desired result cannot be expressed as "one later plugin wins over one earlier plugin," stop sorting and audit/patch the conflict.
The source-mined principle comes from BB84's Vortex-era sorting lesson and the later xEdit "终极奥义": order is theoretically replaceable by a final compatibility patch, but patching every conflicting FormID in a real pack is not realistic. A sane order reduces the patch surface; it does not eliminate patching.
dotdigraph sort_or_patch { rankdir=TB; start [label="Conflict or ordering question", shape=doublecircle]; exists [label="Do the involved plugins actually load and have valid masters?", shape=diamond]; fixfile [label="Fix plugins.txt/loadorder.txt validity first", shape=box]; author [label="Does the mod author specify order or patch requirement?", shape=diamond]; obey [label="Follow author instruction; verify with xEdit/readback", shape=box]; winner [label="Can one plugin/archive win wholesale without losing needed data?", shape=diamond]; sort [label="Solve by order: later winner goes after earlier loser; mirror loadorder.txt in MO2", shape=box]; stitch [label="Need fields/data from multiple plugins in one final state?", shape=diamond]; patch [label="Hand off to xedit-conflict-audit / xedit-automation and build or inspect a patch", shape=box]; group [label="Is this about a per-game group template (lighting/weather/major compatibility-fix style)?", shape=diamond]; kb [label="Query KB domain=load-order for the target game; if silent, mark [GAP]", shape=box]; done [label="Verify winning override / loaded file chain", shape=doublecircle]; start -> exists; exists -> fixfile [label="no"]; exists -> author [label="yes"]; fixfile -> done; author -> obey [label="yes"]; author -> winner [label="no"]; obey -> done; winner -> sort [label="yes"]; winner -> stitch [label="no"]; sort -> done; stitch -> patch [label="yes"]; stitch -> group [label="not sure"]; patch -> done; group -> kb [label="yes"]; group -> patch [label="no"]; kb -> done; }
after a later-wins cascade.
preserved together in one final winning record.
so order can be reasoned about in batches; same-group conflicts still need a specific winner or a patch.
from the current runtime as described below; user-managed patches generally live late because they intentionally carry final stitched decisions.
edits from a content mod. Example principle: if one mod imposes the pack-wide equipment-slot rule and another content mod casually edits one vanilla slot, the system-rule mod usually belongs later. Verify the actual records.
major compatibility-fix placement, major overhauls, or game-specific community group layouts, query the KB first:
text bgs_kb_query({ query: "load order group template lighting weather patch", games: ["<Game>"], domains: ["load-order"] })
If the KB is silent, mark [GAP] instead of inventing a generic position.
| Situation | Default | |---|---| | Beginner / small pack, no author instruction, no known conflict | Use LOOT or the manager's automatic sort as a baseline, then validate. | | Author specifies order, dependency, or required compatibility patch | Follow the author first; verify with xEdit/readback. | | xEdit shows the automatic result chose the wrong winner | Manually reorder if one winner is enough; patch if fields must be stitched. | | Per-game group placement question | Query KB load-order records; do not hardcode a cross-game template in this skill. | | Recurring conflict family across many mods | Create/adjust a group rule, then patch only the records the group rule cannot express. |
| Thought | Reality | |---|---| | "排序无所谓,xEdit能补一切." | True only in principle; exhaustive FormID stitching is not realistic at pack scale. Sort first to reduce the patch surface. | | "LOOT / auto-sort ran, so ordering judgment is done." | Auto-sort is a baseline. It cannot know every pack-specific winner or every author-required exception. | | "Same group means no conflict." | Same group means conflicts should be rare. When two same-group mods touch the same record, decide winner or patch. | | "Manager UI shows no conflict, so there is no conflict." | Record conflicts require xEdit readback. Asset/archive conflicts require asset-precedence inspection. | | "Just put every patch last and forget the rest." | Patches late is correct, but a patch can only express decisions you actually audited. | | "Lighting/weather/major compatibility-fix placement is universal." | Those are per-game template facts. Query KB and mark [GAP] if the pack has no record. |
| Excuse | Reality | |---|---| | "I'll patch everything later." | That is the impossible endgame. A sane order is how you avoid patching irrelevant conflicts one by one. | | "Manual sorting is just vibes." | Manual sorting is only legitimate when tied to a known winner, author instruction, group rule, or xEdit readback. | | "The content mod should win because it adds new things." | Content mods often carry incidental edits. A systemic-rule mod may be the right later winner. | | "If two mods are incompatible, sorting harder will fix it." | Some conflicts are ordering conflicts; some are real incompatibilities. Escalate to audit instead of looping order changes. | | "Archive conflicts are invisible, so ignore them." | Invisibility is why BA2/BSA precedence must be inspected rather than guessed. |
If sorting does not produce the intended winning override, hand off to xedit-conflict-audit: inspect the record, name the winning override, decide whether the current winner is safe, and only then route to patch authoring.
The engine loads each game's official plugins at fixed positions before reading the user-managed plugins.txt. The exact set depends on the target game, installed DLC, and any Creation Club / verified-content bundles.
Do not hardcode a per-game vanilla-master list in your workflow. Instead, derive the official masters from the user's actual MO2-managed runtime:
<MO2_Root>\ModOrganizer.ini to learn gameName and gamePath.xedit_call({ command: "files.list", args: {} })and look at the earliest, auto-loaded official plugins. Treat those as the immutable official master set.
<gamePath>\Data)and known official DLC/content files there. Do not add, remove, or reorder them in your generated plugins.txt.
libloadorder's writer skips these early-loading official plugins on save; MO2 re-injects them as active at read time. So whether they appear in the file or not, they load first.
Practical rule for agent-authored plugins.txt: omit the official masters you inferred from the actual target runtime. Start your file with user-managed plugins instead.
Prefix the line with *. Position unchanged.
Before:
ArmorKeywords.esmAfter:
*ArmorKeywords.esmStrip the leading *. Position preserved (the plugin stays in the file).
Before:
*HUDFramework.esmAfter:
HUDFramework.esmDelete the whole line. Position is dropped. (MO2 will re-append it as inactive at the end of loadorder.txt on next read — plugins.txt itself stays clean.)
Cut the line, paste it after Y. Mirror the change in loadorder.txt if it exists (MO2 maintains both files; out-of-sync state confuses MO2).
Append at the bottom with * if you want it active.
*MyExistingMod.esp
*JustInstalledMod.esp ← new line at the endThe bottom = loads last = wins conflicts with everything above. If you don't want it to win conflicts, move it higher.
Do NOT do this by editing plugins.txt. The light-plugin flag lives in the plugin's file header, not in the load-order file. Route through the xEdit daemon:
xedit_call({ command: "plugin.esl.analyze", args: { file: "MyMod.esp" } }) — checks whether the plugin's FormIDs fit in the ESL FE-slot range.xedit_call({ command: "plugin.esl.apply", args: { file: "MyMod.esp" } }) — sets the light-plugin flag in the file header.After flagging, the file extension stays .esp. The engine reads the new flag at load time and remaps the plugin into the shared FE slot.
plugins.txt does NOT change as part of ESL conversion.
| Operation | Right path | Why | |---|---|---| | Activate / deactivate a plugin | Edit plugins.txt (toggle *) | No daemon verb exists for activation; the daemon manipulates plugin contents, not the activation file. | | Reorder plugins | Edit plugins.txt + mirror in loadorder.txt | xEdit docs 2.3 (verbatim): "Load order cannot be changed with xEdit." | | Remove a plugin entry | Edit plugins.txt | Same reason. | | Add new plugin to load order | Edit plugins.txt (append) | Daemon doesn't write the activation file. MO2 will project the mod's .esp via VFS once the file references it. | | Check a plugin's masters | xedit_call({command:"files.get_masters", args:{file:"..."}}) | Reads the plugin header. | | Add a missing master to a plugin | xedit_call({command:"files.add_required_masters", args:{...}}) | Mutates the file header. | | Convert ESP → ESL | plugin.esl.analyze → plugin.esl.apply | Sets header flag; load-order file unchanged. | | Clean ITM / UDR | xEdit launcher with -quickAutoClean OR daemon files.clean_masters | Both work; CLI faster for batch. | | Sort the load order | External LOOT | Neither xEdit nor MO2 sorts; LOOT does, then writes plugins.txt. | | Verify a load order is valid | Combine: read plugins.txt, then daemon files.list to confirm each *-prefixed file exists with required masters present. | Two-sided: file presence (libloadorder) + header consistency (xEdit). |
The rule of thumb: plugins.txt is an activation surface owned by MO2 (or LOOT, or the agent). The xEdit daemon never touches it. The daemon's domain ends at the file header of individual plugins.
When you want xEdit to load only a subset of mods (e.g., to isolate a conflict between two specific plugins), generate a custom plugins.txt under an agent-owned artifacts path and pass it to xedit_start:
typescript// 1. Write the file const customPlugins = `# Agent-generated for conflict isolation between PluginA + PluginB *<PrimaryGameMaster>.esm *<OptionalCommunityFix>.esp *PluginA.esp *PluginB.esp `; await writeFile("<agent-owned-artifacts-path>/foo-vs-bar/plugins.txt", customPlugins); // 2. Start xEdit pointing at the custom file + the right Data dir await xedit_start({ pluginsFile: "<agent-owned-artifacts-path>/foo-vs-bar/plugins.txt", dataPath: "<MO2_Root>/<managed game root>/Data", gameMode: "<GameMode>", });
Notes for the experimental file:
to make the experiment self-describing, but you do not need to. xEdit auto- loads the official masters from the Data dir regardless.
in ASCII).
| File | What it lists | Prefix convention | Where | |---|---|---|---| | plugins.txt | .esp/.esm/.esl plugin filenames | * = active, no prefix = inactive | <profile>/plugins.txt | | modlist.txt | MO2 mod folder names (under mods/) | + = enabled, - = disabled, * = foreign | <profile>/modlist.txt |
The * in modlist.txt means "foreign mod" (MO2-managed but externally owned), NOT "active." Mixing the two formats is the #1 way to corrupt a profile. Never copy/paste between them.
Before launching xEdit via the agent, read MO2's config to learn the managed game path:
powershell# <MO2_Root>\ModOrganizer.ini contains lines like: gameName=Fallout 4 gamePath=@ByteArray(D:\\awesome-bgs-mod-master\\.artifacts\\mo2\\Stock Game\\Fallout 4)
The gamePath value (strip the @ByteArray(...) wrapper) is where the agent's xedit_start({ dataPath: ... }) should point. Specifically, the Data directory is <gamePath>\Data. Without an explicit dataPath, xEdit falls back to the Windows registry — which points at the platform install path, not necessarily the MO2-managed game root. That's the source of "wrong Data" bugs.
Three options for catching a malformed plugins.txt before launching xEdit into a broken state:
-quickAutoClean against thefile. Non-zero exit = a master is missing or a *-prefixed plugin doesn't resolve. Cheap and authoritative. xEdit.exe -fo4 -D:"...\Data\" -P:"...\plugins.txt" -veryquickshowconflicts
errors in its GUI / log.
*-prefixed plugin must exist as a file in theData dir; no duplicate lines; under 255 active full plugins + under 4096 active light plugins (.esl + flagged-ESP).
What makes a file invalid:
next bullet).
*-prefixed line whose file does not exist in the Data dir.The OLD format used by pre-asterisk games:
* prefix. Presence of a plugin line in plugins.txt means it'sactive. Absence means it's not loaded.
loadorder.txt is the canonical full-order file (active + inactive).plugins.txt contains only active plugins.
plugins.txt uses Windows-1252 encoding; loadorder.txt uses UTF-8without BOM.
This format does NOT apply to FO4 / SSE / Starfield. If you're targeting one of these older games, use this section's rules; for everything else, use the asterisk format above.
xedit-automation — hub skill for all xEdit work; routing doctrine,anti-patterns, sub-agent recipes.
knowledge/bgs-kb/packs/core/records/ — daemon command,error-code, save-semantics, and glossary facts formerly kept in the retired xedit-automation/xedit-knowledgebase.md redirect.
setting-up-bgs-modding-environment — explains how to inspect MO2'sModOrganizer.ini for gamePath before launching xEdit.
-P:,-D:, and friends.
Ortham/libloadorder documentation — the authoritative source for theasterisk format semantics.
Other measured skills in the registry, with their headline benchmark lift.