This is the season of the Forge of Days – the hottest August day in the UK for the last decade – so here’s something apposite for you.

I’ve been quiet recently, for two reasons. One is that last month, Lottie finally cajoled me into taking a couple of weeks off. (I now have to return the favour, which is going to be a toughie because her work ethic makes mine look like a half-articulated preference.) But the other is that I’ve been rewriting some core parts of the Cultist Simulator code base, so I can reuse more of it for BOOK OF HOURS.

The rewrite is on the beta branches on GOG and Steam now. There are some performance improvements (and probably some exciting new bugs), but the big visible change is an update to the modding framework – especially, integration with the Steam Workshop.

Our Steam Workshop page is named for the Invisible Serapeum: the library in EXILE which, unusually for a library, claims the patronage of the Forge of Days.

If you’re interested in playing mods, then just keep an eye on the Steam Workshop to see what shows up (no news on a GOG workshop-like, but you can still install mods manually). If you’re interested in making mods, read on…

All these changes, including the Steam Workshop, currently only function with the beta (gateofhorn) branch. Please let us know about bugs at

Uploading a Mod to the Serapeum

  1. Add the mod to the /mods folder in the Cultist save folder, as per usual.
  2. Start the game and hit the ‘DLC & Mods’ button
  3. Hit ‘Upload’. You should get a message confirming success or lamenting failure, and a window showing the Woklshop item.
  4. Subscribe to the item and restart the game; the Steam version of the mod should show up under Mods.
  5. Once you’ve uploaded a mod, you’ll get a file called serapeum_catalogue_number.txt in the local mod folder. As long as this is in the local mod folder and you’re the originally authenticated user, you can update the mod.

Modding Framework Changes [updated 12/08/2020]

I’ve updated Marc’s original modding post here. Existing mods will need some changes, but it’s a matter of find/replace and renaming some files.

  • If you add “newstart”: true to a legacy in a mod, it’ll show up in the INVISIBLE SERAPEUM on the menu page, and players will be able to start it as if it were a piece of DLC.
  • You can also now use tablecoverimage:, tablesurfaceimage:, and tableedgeimage: on Legacies to customise table appearance.
  • if you add a file to the mod root called cover.png, it’ll be used as a preview image for the mod, in the game and on Steam.
  • Modding and core files now require strict JSON, not the weird relaxed hybrid I’ve preferred. That basically means quoting keys as strings: “label”: “Teresa”, not label: “Teresa” .
  • A lot of you sensible folk have used strict JSON anyway; if you need to tidy up non-strict JSON, there are a bunch of free online tools and add-ins that will do it with a click. Google ’em and pick the one you prefer.
  • manifest.json is now synopsis.json, to provide a simple at-a-glance way of seeing whether it’s old or new format.
  • I’ve renamed some properties for consistency:
DeckEffect -> DeckEffects
AlternativeRecipes-> Alt
LinkedRecipes -> Linked
FilterOnAspectId -> Filter
MutateAspectId ->Mutate
MutationLevel -> Level
[on Verbs] Slots-> Slot
  • I’ve rationalised our frankly arcane image folders. You’ll now find images in
  • Mod files can no longer contain multiple entity types (e.g. both recipes and elements) – one file, one entity type (though you can have as many files for one entity type as you like). Sorry, this is just me making my life easier.
  • The property manipulations in the modding framework are still available, except for $plus and $minus, which I’ve removed because the kind of things that could be done with them were likely to cause problems. I kept confusing $extends (which adds items to a collection) and extend (which inherits properties from an existing entity) so I’ve also renamed $extends to $add.

There are a lot more changes coming, but the ones above should, I hope, be all the breaking changes.

Have fun with this lot. My whole approach now is to make the Cultist code a bit more general-purpose. ngl, this is primarily for our own benefit – the more we can reuse it for BOOK OF HOURS, the better – but if we can reuse the same content framework for two very, very different games, then the most ambitious amongst you should be able to go properly wild with it. Welcome to the House without Walls.


  1. I don’t know what other additions you want to make, but just in case I’ll list some things I’m personally missing in the CS modding (and which would make sense to have in general) and which hopefully are not that hard to implement:
    – Being able to reference other elements’ quantity in purges and mutations (like requirements can after the Exile). Something like
    “purge”: { “funds”: “expenses” }

    – Being able to create customized challenges with breakpoints like
    “challenges”: { “aspect”: { 1: 0%, 5: 50%, 10: 90% } }
    (ideally, you’ll be able to specify if chance grows linearly in-between breakpoints, like in the example above having aspect of 2 intensity will pass the challenge with the 20% chance; but I understand that it’s less convenient syntax-wise)

    – extantreqs, tablereqs and usual requirements being unified; you could access “table” and “extant” like
    “required”: { passion : 1, : 1, extant.reason : 1 }

    Not once I’ve crashed into those limitations during mod planning, and having at least some of those fixed would be really nice.

    1. >– Being able to reference other elements’ quantity in purges and mutations (like requirements can after the Exile). Something like “purge”: { “funds”: “expenses” }

      This is a good idea, and is quite likely to happen, because I’d like to rationalise these properties to use the same approach

      > – Being able to create customized challenges with breakpoints like “challenges”: { “aspect”: { 1: 0%, 5: 50%, 10: 90% } }

      This is also a good idea, but isn’t a priority for me…

      *but* if you poke around the source code, you’ll notice (since the rewrite) it’s a much more data-centric approach, where you can use [FucineEntity] and [FucineValue] attributes to tell classes they should populate themselves from the json. I expect to add some stuff to the framework to load assemblies from mods and make it easier for people to write and inject their own code

      >– extantreqs, tablereqs and usual requirements being unified; you could access “table” and “extant” like
      >“required”: { passion : 1, : 1, extant.reason : 1 }

      I’d rather keep those separate because keywords like ‘table’ and ‘extant’ can end up in the actual ids of keys! but never say never

  2. Thanks for the short answer.

    Yes, didn’t think about “” being a legit element name. But you probably can use special symbols, like “required: { table#health : 1 }” to separate scope-defining and element-defining clearly. I totally understand that it’s a very situational request and don’t insist (and not in any position to do so, of course), but it just feels very right to be able to do all the checks in the same place………..
    (and, actually and more importantly, to mix different types of checks like “required: { wounds : table#health }” )

    But being able to inject your own code without tightroping with Reflections deprecates most of such specific requests, of course.

  3. Thank you very very very much for making the workshop publishing process be so insanely simple! One click!!! I already put 4 mods on the workshop, I hope to see so many more in the future 🙂

  4. “Mod files are always loaded after the base game’s “core/” folders, but before any localisation data (eg core_ru/, core_zh).”
    – Why? This broke my tooltip mod, how do I edit localised descriptions or e.g. labels now? Them become owerwritten on any language except english.

    “If you add mod-specific loc files, they’ll work” – How?

    “there’s no explicit support for installing loc for mods quite yet” – do you have plans on that? My approach with three folders like in game “core/elements”, “core_ru/elements”, “core_zh-hans/elements” ended up in black screen instead of game main menu (menu persisted, i heared sounds moving cursor down’em)…


Leave a Reply to William JenningsCancel reply