Skip to content

Skyrim Modding Substrate Survey (Merged)

Two independently commissioned research reports (referred to below as [Gemini] and [Compass]) answer the same question: survey the Skyrim modding ecosystem — AI-NPC frameworks, SKSE event hooks, AI package/schedule override mods, prior reputation/rumor mods, and NPC data sources — and recommend what Chronicle should build on, fork, or study. This document merges both into one filed reference.

Verified 2026-08-20: three factual disagreements between the two source reports (MinAI status, Mantella's latest release date, CHIM's license) were resolved directly against the GitHub API rather than re-researched — see docs/decisions/open-questions.md for the verification detail. This file has been corrected in place; the SkyrimNet build-vs-study disagreement is a genuine open question, not a factual one, and remains tracked in open-questions.md.

Findings

  • [DISAGREEMENT / DESIGN-INPUT] Which existing framework to anchor on differs sharply between the two reports. [Gemini] recommends treating Mantella as the primary architecture to study (decoupled Python service + SKSE_HTTP, AGPL-3.0/MIT) and does not mention SkyrimNet's Papyrus/C++ extension API at all — it only credits SkyrimNet with an in-process memory-reading pattern. [Compass] instead identifies SkyrimNet (MinLL/SkyrimNet-GamePlugin) as the single best integration target because of its documented RegisterEvent/RegisterPackage/RegisterDecorator/DirectNarration API, and downgrades Mantella and CHIM to "study the transport only." This is a first-order architectural fork for Chronicle: build-to-integrate against SkyrimNet's live API vs. build a standalone SKSE_HTTP-style bridge modeled on Mantella. See Details §1.
  • [RISK] SkyrimNet is the most capability-aligned integration target but is closed-source with no declared license. [Compass] is explicit: no LICENSE file, DLL distributed only via Releases, C++ core closed. [Gemini] doesn't flag this risk at all because it doesn't treat SkyrimNet as a build-on candidate. Before committing to SkyrimNet as a dependency, Chronicle needs explicit license clearance from the author (MinLL) — this blocks any "integrate, don't fork" plan.
  • [BUILD-ON] Both reports agree: do not route high-frequency social-sim events through Papyrus. Papyrus script-queue lag is independently identified as the failure mode of the historical Skyrim Reputation mod ([Gemini] and [Compass] both cite it) and as an architectural anti-pattern for real-time event ingestion. Consensus: use a native SKSE C++ plugin (CommonLibSSE-NG) hooking RE::ScriptEventSourceHolder/native Papyrus events directly, pushing JSON over HTTP or WebSocket to the external Python process, bypassing the Papyrus VM for anything above low-frequency events.
  • [BUILD-ON] Both reports converge on the same event set and transport building blocks as fallback/standalone options: powerofthree's Papyrus Extender (open source, ~442 functions / 82 events) as the event-expansion layer, and Leidtier's SKSE_HTTP (license unconfirmed per [Compass]) or a custom CommonLibSSE-NG WebSocket plugin as the transport — this is the same stack Mantella itself uses.
  • [DESIGN-INPUT] Both reports independently converge on a "dual-state" / cell-hydration architecture as mandatory. Skyrim only fully simulates NPCs in the loaded cell grid (~3x3–5x5 cells); off-grid NPCs are inert beyond abstract schedule interpolation. Both reports specify the same pattern: maintain the full ~1,000-NPC belief/rumor graph symbolically in Python at all times, and on TESCellAttachDetachEvent/OnCellAttach/OnCellDetach hydrate/dehydrate state (inject AI packages, relationship overrides, prompt context) only for actors currently in the loaded grid. [Compass] adds a specific engine caveat neither report can ignore: unloaded NPCs' schedule position is only updated for up to ~1 hour after wait/sleep/fast-travel, so Chronicle must model NPC location itself off-grid rather than trust the engine, or depend on the community fix "NPC AI Process Position Fix – NG" (Nexus 69326).
  • [BUILD-ON] Both reports agree Mutagen/xEdit-based programmatic extraction from Skyrim.esm/Update.esm/DLC plugins (NPC_, FACT, RELA, PACK records) is the correct ground-truth data pipeline, merged with UESP lore text (CC-BY-SA) for bios. [Gemini] names Mutagen/Synthesis (C#/.NET, GPL-3.0, active 2026) specifically; [Compass] names the "Info NPC Extractor xEdit Script" (Nexus SE 159144, Pascal/xEdit, purpose-built for Mantella/CHIM/SPID pipelines) as the best starting point. Both are viable extraction routes to the same target schema — pick one, don't build a third from scratch.
  • [RISK] Both reports agree vanilla relationship (RELA) data is sparse relative to Chronicle's ambitions. [Compass] gives a concrete data point: a relationship-mod author found only "586 relationships across 397 NPCs" via xEdit on vanilla data. Chronicle will need to synthesize the bulk of its ~1,000-NPC relationship graph rather than harvest it wholesale.
  • [DESIGN-INPUT] Both reports agree no prior reputation/rumor mod solved propagation — this is genuinely Chronicle's gap to fill. Skyrim Reputation is a global morality scoreboard (not per-NPC, not propagating); rumor mods (Rumors of Skyrim, Rumors like in Oblivion) are static dialogue pools gated by crime-gold counters, not systems where NPCs learn/believe/forward information. Both reports independently conclude this validates Chronicle's core thesis rather than threatens it.
  • [RISK] An engine update is a live near-term threat. [Compass] flags that Bethesda announced an incoming Skyrim SE/AE update (noted Aug 14, 2026) that will historically break every native SKSE plugin (SkyrimNet, SKSE_HTTP, Papyrus Extender, Skyrim Platform) until updated. [Gemini] does not mention this. Design implication: keep the Python/DB side of Chronicle decoupled enough that only the thin in-game SKSE bridge needs a rebuild after engine updates.
  • [DEFER] Both reports treat CHIM/HerikaServer's PHP+PostgreSQL(+WSL2) stack and MinAI as study-only, not adoption candidates. MinAI is confirmed deprecated by its own README ("no longer maintained... use SkyrimNet instead"), last release 2.1.3 (April 2025). CHIM's vector-embedding RAG memory design and its DB-migration plugin-manifest model ([Compass]: bind Papyrus to CHIM_CommandReceived, register manifest.json with git_repo/SQL migrations/) are worth studying as design references but neither report recommends running the PHP/PSQL/WSL stack.
  • [DEFER] Organic Factions (EtherDynamics) and static AI-schedule overhaul mods (Immersive Citizens, AI Overhaul SSE) are study-only, cautionary examples, not architectural targets — both stalled/became brittle due to Creation-Kit authoring overhead and load-order/priority conflicts with vanilla quest systems, reinforcing the case for driving AI packages at runtime from Python rather than authoring them statically.

Details

1. AI-NPC frameworks

Framework Repo License Last maintained Architecture [Gemini] verdict [Compass] verdict
Mantella art-from-the-machine/Mantella + Mantella-Spell Backend AGPL-3.0; Mantella-Spell MIT; bios CC-BY-SA v0.14, confirmed published 2026-04-21 (verified via GitHub API; [Gemini]'s "December 2025" was stale) Decoupled Python backend (main.py, Python 3.11) + Papyrus spell mod; moved from file polling to async HTTP via Leidtier's SKSE_HTTP in the v0.12 "Road to HTTP" rework (issue #230) Study architecture / reuse IPC substrate. Study client-side event forwarding and HTTP wrappers; don't build the sim inside Mantella's backend (it's tuned for real-time 1:1 dialogue, STT/TTS). Study the transport, optionally target as a second transport. Quest-tracks-conversation + HTTP-events pattern and CSV bio pipeline (skyrim_characters.csv) are reusable. AGPL means forking+serving obligates source disclosure.
Pantella Pathos14489/Pantella AGPL-3.0 Active fork, 2025 Fork of Mantella expanding local LLM backends (KoboldCpp, Llama 3, Gemma) and TTS routing; per [Compass], more transparent launcher, 1,000+ NPC bios Study — reference for multi-backend LLM/TTS routing. Noted as a fork worth knowing.
CHIM (HerikaServer) abeiro/HerikaServer MIT (MIT-LICENSE); bios CC-BY-SA Active, "March 2026" / 4,000+ commits, issues into late 2025, no tagged releases SKSE native DLL (aiagent.dll/AIAgent.esp) → WSL2 Debian VM ("DwemerDistro") running Apache2+PHP+PostgreSQL with ~500MB local vector embedding model for RAG memory Study memory/RAG pipeline; bypass the PHP/PostgreSQL stack. Study, don't build on — the WSL2/PHP/PSQL footprint is exactly what to avoid. But: timestamped "Events" log (chronology every NPC pulls last-N events from for prompt context), faction/location sync, and documented plugin system (bind to CHIM_CommandReceived ModEvent, register manifest.json with git_repo+SQL migrations/) are strong design references.
MinAI MinLL/MinAI No LICENSE file (all-rights-reserved) Last release 2.1.3, April 2025 — confirmed deprecated PHP-plugin/Papyrus middleware extending CHIM; modular context builder; "Sapience" (SPID-driven AI-perception toggling); "Dungeon Master" hotkeys for injecting narrative events Study context builders & Sapience — adapt the modular context-serialization design for Python state rendering. Deprecated — study only. README states "no longer maintained... use SkyrimNet instead." Modders' Guide exposed key/value state-push mod-events and faction-based action gating (minai_NoActionsFaction) — study the design, use SkyrimNet's live API instead.
SkyrimNet MinLL/SkyrimNet-GamePlugin No LICENSE file — closed-source DLL, distributed only via Releases Active; Beta 23 hotfix as of mid-2026 build cycle (35 releases, 700+ commits) Single in-process SKSE C++ DLL; reads game memory directly; serves React dashboard/API on localhost:8080; worker threads; 7 specialized LLM roles Study direct memory event piping — replicate the pattern of reading memory pointers without IPC serialization overhead; not treated as an integration target. Build on / integrate — best-aligned, per [Compass]. Documented Papyrus API (SkyrimNetApi) + public C++ DLL API: RegisterEvent, RegisterShortLivedEvent (TTL-bounded), RegisterAction/RegisterSubCategory/RegisterTag/RegisterDecorator, RegisterPackage/UnregisterPackage/ScheduleDelayedPackageRemoval/ClearAllPackages/HasPackage (runtime AI-package injection), DirectNarration, SendCustomPromptToLLM; lifecycle ModEvents (SkyrimNet_SpeechStarted, SkyrimNet_MemoryCreated, SkyrimNet_DiaryCreated); vector-embedded memory CRUD; Inja template system with 100+ decorators. Third-party ecosystem already builds world-state-driven systems on it (SeverActions: 38+ NPC actions; IntelEngine: autonomous NPC "Story Engine" DM). Caveat: closed DLL/unstated license — confirm licensing before building a distributed product on it.

Note on disagreement: [Gemini]'s architectural recommendation section never proposes integrating with SkyrimNet's API at all — its blueprint is "custom SKSE plugin (CommonLibSSE-NG) + MinAI-style context builder + Mutagen ingestion," treating Mantella/CHIM/SkyrimNet uniformly as study-only prior art. [Compass] stages SkyrimNet-integration as the fastest path to a working prototype (Stage 1) with a standalone-bridge fallback (Stage 2) only if SkyrimNet's license or API stability becomes a blocker. Chronicle's team should treat this as an open decision, not resolved by the survey — see the flagged disagreement in Findings.

2. SKSE event hooks and event-forwarding bridges

Native/hookable events (both reports; [Gemini] frames these as C++ engine dispatcher classes via CommonLibSSE-NG, [Compass] frames the same surface via Papyrus script events plus extender functions):

Event Source Utility
TESDeathEvent / OnDeath, OnDying, OnEnterBleedout RE::ScriptEventSourceHolder Grudge resolution, inheritance, grief, high-severity rumor generation
TESContainerChangedEvent / OnItemAdded, OnItemRemoved, OnContainerChanged ditto Theft, bartering, gift-giving, obligation shifts
TESActivateEvent / OnActivate ditto Physical contact, door transitions, container searching
TESCombatEvent / OnCombatStateChanged, OnHit ditto Violent-conflict evidence, hostility spikes
TESActorLocationChangeEvent / OnLocationChange ditto Spatial rumor propagation
TESCellAttachDetachEvent / OnCellAttach, OnCellDetach, OnCellLoad ditto Symbolic-vs-hydrated simulation transition
TESEquipEvent / OnEquip, OnUnequip ditto Visual/faction-armor state context
Crime events (crime gold, discover-dead-body, assault, theft/pickpocket via faction+crime-gold checks) Story Manager quest-start events [Compass] only — direct crime-detection input for grudge/rumor triggers
Package/schedule (OnPackageStart/OnPackageChange, OnSit/OnGetUp) Papyrus [Compass] only — know when NPC behavior changes

Transport/bridge options (consensus + additions):

  • Custom SKSE C++ plugin (CommonLibSSE-NG) hooking native dispatchers directly, pushing JSON via WebSocket/HTTP — both reports' top recommendation for the performant path. [Compass] names a concrete template: SkyrimScripting/SKSE_Template_WebSockets (supports SE/AE/GOG/VR).
  • powerofthree's Papyrus Extender (powerof3/PapyrusExtenderSSE, Nexus 22854) — open source, "~442 functions, 82 events" per [Compass]; a near-universal dependency (CHIM requires it). Both reports treat it as the standard event-expansion layer.
  • Leidtier's SKSE_HTTP (Leidtier/SKSE_HTTP) — the mechanism Mantella uses; Papyrus builds typed dicts, serializes to JSON, POSTs, receives replies via SKSE_HTTP_OnHttpReplyReceived/OnHttpErrorReceived ModEvents. [Compass] flags license as unconfirmed — verify before depending on/redistributing.
  • Skyrim Platform (skymp project, skyrim-multiplayer/skymp, GPL-3.0) — [Compass] only. Full JS/TS runtime in-process, rich on(event) system, engine-function hooks (sendAnimationEvent, sendPapyrusEvent). Heavier dependency; GPL forces source disclosure of forks.
  • Kris's Papyrus Extender (Nexus 115164) and PAPER (DennisSoemers/PAPER) — [Compass] only, additional batch item events (OnBatchItemsAdded/Removed) and impact events.

Piping high-frequency events (location/container changes) through Papyrus SendModEvent scripts is called out by both reports as a bottleneck to avoid — this is the same lesson drawn from Skyrim Reputation's failure (§4).

3. AI package/schedule override and cell hydration

  • Skyrim NPCs run behavior via TESPackage stacks (Sandbox, Travel, Patrol, UseItemAt, Eat, Sleep), evaluated by priority; Actor.EvaluatePackage() forces re-evaluation. Both reports describe using SPID (Spell Perk Item Distributor) to assign custom packages at runtime by actor ID/faction/keyword, then triggering evaluation.
  • [Gemini]: SKSE plugin sets a Global Variable or quest-alias-driven package, then calls EvaluatePackage().
  • [Compass]: prefers SkyrimNet's RegisterPackage/UnregisterPackage/ScheduleDelayedPackageRemoval as "the best available runtime API" if integrating with SkyrimNet; IntelEngine (third-party, built on SkyrimNet) already uses this to make NPCs physically travel/act. Falls back to Papyrus + powerofthree helpers if standalone.
  • Static schedule-overhaul mods — Immersive Citizens – AI Overhaul (Nexus 173) and AI Overhaul SSE (Nexus 21654) — are [Compass]-only cautionary examples: ESP-record-based (load-time, not runtime), mutually incompatible, load-order-sensitive; Immersive Citizens is "effectively frozen and hostile to third-party patching." Cited as proof of the package-priority conflict surface Chronicle will face when pushing runtime packages against vanilla quest AI.
  • Cell hydration, both reports agree: NPCs in the loaded grid (~3x3–5x5 cells) are fully hydrated TESObjectREFR objects with physics/pathfinding/AI updates; off-grid NPCs are abstract (position interpolated along schedule/road paths, no collision/script execution). Dual-state pattern: Python simulates the full 1,000-NPC belief/spatial graph continuously; on cell attach/detach events, hydrate/dehydrate active game-state overrides (relationship overrides, dialogue flags, AI packages).
  • [Compass]-only engine caveat: Skyrim only updates an unloaded NPC's schedule position for up to ~1 hour after wait/sleep/fast-travel — off-screen NPC positions can go stale relative to their schedule. Mitigation cited: NPC AI Process Position Fix – NG (Nexus 69326), or Chronicle must model this itself.

4. Prior reputation/rumor/consequence mods

Mod Repo/Link License/status Approach Why it stalled
Skyrim Reputation Nexus SE 22374 Open/Nexus standard; released 2018, patches active ~2023 Pure Papyrus quest-topic conditions modifying dialogue by regional/global "alignment"/morality score; MCM toggle; guard/NPC greetings react to a title Global reputation math ran on Papyrus thread queues → latency; broad dialogue-condition overrides clobbered unique NPC quest greetings; tracking was global, not interpersonal (an NPC in Markarth reacts instantly to a Riften crime, no propagation delay). Community had to ship "Skyrim Reputation – Fixed and Patched" (Nexus 42538) plus Enai-mod compatibility patches.
Organic Factions Nexus SSE 10289, EtherDynamics Open framework / proprietary extension; ~2022 Custom C++/Enhanced AI Framework: factions accumulate wealth, recruit, capture territory independent of player level [Gemini]-detailed: extreme Creation-Kit authoring overhead (dozens of linked refs/templates per faction) and instability from hooking vanilla quest systems (Civil War) that rely on hardcoded stage triggers/static actor locations.
Rumors of Skyrim / Voiced Nexus SE 177826 [Compass]-only: 50–59 new dialogue lines, optional "crime framework" gating lines by crime-gold counts Static dialogue pool triggered by thresholds — no NPC learns/believes/forwards anything; "framework" is just a counter.
Rumors like in Oblivion Nexus 21002 [Compass]-only: same static-pool pattern Same limitation as above.
NPCs React To Necromancy (And More) Nexus 70428 [Compass]-only: cooldown-gated reaction lines Reaction, not persistent state.

Both reports converge on the same lesson independent of which specific mods they emphasize: keep belief/reputation calculation entirely out of Papyrus and out of static dialogue conditions; inject context dynamically from the external Python service instead.

5. NPC data sources

Source Link License Notes
Creation Kit master records (.esm) Native engine files (Skyrim.esm, Update.esm, DLCs) Commercial/proprietary NPC_ (base actor/voice type), FACT (faction structure/rank/crime group/inter-faction disposition), RELA (directed relationship rank, −4 Archenemy to +4 Lover on [Gemini]'s cited scale), PACK (24-hr AI schedule). Primary ground-truth source, both reports agree.
Mutagen / Synthesis Mutagen-Modding/Synthesis GPL-3.0 [Gemini]'s preferred extraction tool — C#/.NET library reading/parsing/exporting binary record graphs; active 2026. Related: tr4wzified/ExperienceMutagenPatcher.
Spriggit integrated in Mantella-Spell Open source [Gemini]: converts binary .esm/.esp to YAML — useful for inspection/version control, Mutagen preferred for automated extraction.
Info NPC Extractor xEdit Script Nexus SE 159144 [Compass]'s preferred extraction tool — Pascal/xEdit script exporting NPC_/ACHR records (name, factions, AI data, race) to CSV/INI, purpose-built for Mantella/CHIM/SPID pipelines.
UESP Skyrim:People, Skyrim:Factions (1,475 faction pages per [Compass]), UESPWiki:CSList CC-BY-SA 3.0 Narrative bios/lore for ~3,000 NPCs (per [Gemini]); already used by Mantella, CHIM, SkyrimNet for bio content.
Kaggle "People of Skyrim" kaggle.com/datasets/muhajipra/people-of-skyrim, scraper at github.com/muhajipra/scrapeskyrimwiki [Compass]-only: scraped via BeautifulSoup4 from UESP infoboxes, 1,009 named characters. Convenient for prototyping; verify against actual load order.
NPCs Have Relationships Nexus SE 140482 [Compass]-only: sanity check on RELA sparsity — author reports "586 relationships across 397 NPCs... I don't really believe that."
The Imperial Library [Compass]-only: hosts cleaned game-data exports for TES titles.

Ingestion pipeline consensus: extract structural graph (NPC_/FACT/RELA/PACK) via Mutagen or xEdit script, merge with UESP (and optionally Kaggle-scraped) lore text, normalize to JSON to seed Chronicle's Python belief/relationship graph on first run. Both reports flag that vanilla RELA coverage is sparse relative to Chronicle's ~1,000-NPC ambitions — most of the relationship graph will need to be synthesized, not harvested.


Open item for an ADR: whether Chronicle integrates against SkyrimNet's API (Compass's Stage 1 recommendation, fastest path but blocked on unconfirmed license/closed DLL) or builds a standalone SKSE_HTTP/WebSocket bridge modeled on Mantella + powerofthree's Papyrus Extender (Gemini's implicit default, and Compass's Stage 2 fallback). Both reports agree the underlying event set, cell-hydration pattern, and data-ingestion pipeline are the same regardless of which transport is chosen.