Forge World YAML contract
This is the complete format Forge World accepts. It is written so a person or a language
model can produce a bundle that validates on the first try. Give this page to your model
(paste it, or point it at https://forgeworld.app/contract.md) and ask it to write a bundle
for your idea. Then paste or upload the result at https://forgeworld.app/validate or
https://forgeworld.app/render.
Forge World is deterministic. The validator below is the same code that renders the mod: if a bundle validates, it renders, and the same YAML always produces the same mod. Errors block a render; warnings do not. Targets Stellaris 4.5.
Bundle
A bundle is one release.yaml plus one or more event files:
release.yaml
events/
first_event.yaml
second_event.yaml
- At most 50 files, each at most 100 KB.
.ymlworks too. - File names don't matter; events are found by their
slug. - On the Render page you can also paste a single event; Forge World wraps it in a draft
release.yamlfor you.
release.yaml
All five fields are required and must be non-empty.
| Field | Meaning |
|---|---|
code |
Mod identifier. Lowercase letters, digits and underscores only, e.g. drifting_museum. |
name |
Mod name shown in the launcher. |
month |
Release month, e.g. '2026-10' (quote it). |
status |
Free text, e.g. draft. |
notes |
Free text, one line is fine. |
Event files
Each event file is one event: a mapping with these fields.
| Field | Required | Meaning |
|---|---|---|
slug |
yes | Unique id within the bundle, lowercase with underscores. Other events refer to it. |
kind |
yes | standalone, anomaly or site (see below). |
name |
yes | Event name. |
interaction_events |
yes | List of interactions (the popups). At least one. |
default_trigger_type |
no | gatekeeper_pool (fires on its own over time; the default) or triggered_only (fires only from another event's trigger_event). |
notes |
no | Free text for yourself. |
site_difficulty |
no | Sites only: 1 to 10, default 3. Each chapter is one step harder. |
Kinds
standalone: an empire event. It fires on its own unless it istriggered_only. Every event fires at most once per game.anomaly: a science ship discovers it while surveying. Needs at least one interaction withrole: anomaly_success; an optionalrole: anomaly_failinteraction plays on failure.site: an archaeological dig site in chapters. Every interaction needschapter_index(1, 2, 3...), and the site has as many stages as interactions. Needs the Ancient Relics story pack in game.
Interactions
Each item in interaction_events:
| Field | Required | Meaning |
|---|---|---|
role |
yes | A name for this interaction. trigger_event links use it (slug/role). Anomalies use anomaly_success and anomaly_fail; sites conventionally use site_chapter. |
title |
yes | Popup title. |
description |
yes | Popup body. Plain text; use >- for long text. |
options |
yes | Non-empty list of buttons. A popup with no options can't be closed, so it's an error. |
chapter_index |
sites | Chapter number, starting at 1. |
picture_hint |
no | An event picture such as GFX_evt_derelict_interior, GFX_evt_archaeological_dig, GFX_evt_alien_ruins, GFX_evt_star_chart, GFX_evt_ancient_databank. Unknown names fall back to a default picture. |
Options
| Field | Required | Meaning |
|---|---|---|
opt_key |
yes | Short id, e.g. A, B. |
text |
yes | Button label. |
effects |
no | List of effects (below). An option with no effects just closes the popup. |
Effects
Every effect has a category and that category's required fields. Any other category is an
error. Amounts are what the player gets: negative numbers are costs.
resource_gain
Add or remove a flat amount.
resource(required): one ofenergy,minerals,food,alloys,consumer_goods,unity,influence,trade,physics_research,society_research,engineering_research(or justphysics,society,engineering),volatile_motes,exotic_gases,rare_crystals,sr_living_metal,sr_zro,sr_dark_matter,nanites,minor_artifacts,astral_threads.amount(required): a number.
resource_gain_scaled
Add or remove a share of the empire's current stockpile, so the cost or reward matters at any stage of the game.
resource(required): as above.percent_of_stockpile(required): a fraction, e.g.-0.08for 8% of the stockpile.min_amount,max_amount(optional): clamp the result. For a loss,min_amountis the larger loss:min_amount: -800, max_amount: -100.
research_progress
Research boost in one field, sized to the empire's research income.
tech_area(required):physics,societyorengineering.progress(required): a fraction such as0.10(about a year of that field's output, capped).
add_tech_progress
tech(required): a technology id, e.g.tech_destroyers.progress(required): fraction of that tech, e.g.0.25.
give_technology / add_research_option
tech(required): a technology id.give_technologygrants it outright;add_research_optionoffers it as a research option.
modifier_add
A timed empire modifier.
modifier_name(required): short id, e.g.archive_debt.duration_days(required): days; 360 is one year.modifier_description(recommended): what players read on hover. Missing it is a warning.modifier_statandmodifier_value(optional, together): the exact effect, e.g.modifier_stat: country_unity_produces_multwithmodifier_value: 0.1for +10% unity. Without them, Forge World picks a stat from words in the name and description.
planet_modifier_add
A timed modifier on the empire's capital planet.
modifier_name,duration_days(required),modifier_description(recommended), as above.modifier_statandmodifier_value(required): a planet-scope stat starting withplanet_orpop_, e.g.planet_stability_addwith5.
add_artifacts
amount(required): minor artifacts to grant.
add_deposit
deposit_type(required): a deposit id such asd_minerals_3. Anomaly events only: the deposit lands on the surveyed planet.
trigger_event
Fire another interaction from this bundle, now or later. This is how follow-ups work.
event_key(required):slug/roleof the target interaction, e.g.strange_signal_followup/main. The slug must exist and the role must be unique in that event. Raw event ids are not accepted; ids are assigned at render time.days_delay(optional): days to wait, 0 or more.
The target event should be triggered_only. Follow-up events are conventionally named
<parent_slug>_followup (or _followup_b and so on), and an event whose slug ends that way
must be triggered_only. A triggered_only event must be kind: standalone.
event_key: PLACEHOLDER also works: it links to the parent's next <parent_slug>_followup*
event, in order.
ethic_shift
ethic_key(required):ethic_authoritarian,ethic_egalitarian,ethic_xenophobe,ethic_xenophile,ethic_militarist,ethic_pacifist,ethic_spiritualistorethic_materialist, or theethic_fanatic_form of any of them.
trait_leader_add
trait_key(required): a leader trait id starting withleader_trait_, e.g.leader_trait_spark_of_genius.leader(optional):ruler(default) orscientist.scientistworks only in anomaly and site events, where a science ship is involved.
spawn_anomaly
anomaly(required): the slug of ananomalyevent in this bundle. It appears on a free planet in a system the empire owns.
opinion_change
Every empire you have met changes its opinion of you. The change fades over about ten years.
opinion_name(required): short id, lowercase with underscores, e.g.museum_thieves.opinion(required): a non-zero number from -200 to 200, e.g.-25.opinion_label(optional): what the diplomacy screen shows, e.g.Stole from the museum. Defaults to the name.
create_project
A research project at your capital. When it completes, it fires an interaction from the bundle.
project_name(required): short id, lowercase with underscores.tech_area(required):physics,societyorengineering.cost(required): research points, e.g.1500.on_complete(required):slug/roleof the interaction to fire. It must be astandaloneevent, usuallytriggered_only.project_title(optional) andproject_description(recommended): what the player reads. Missing the description is a warning.
spawn_fleet
New ships of one class join the empire at its capital, built from one of its own designs.
ship_class(required):corvette,destroyer,cruiser,battleship,scienceorconstructor. Destroyers and up need the empire to have a design of that class.count(optional): 1 to 5, default 1.
Warnings
These don't block a render, but you should read them:
modifier_addorplanet_modifier_addwithoutmodifier_description.create_projectwithoutproject_description.days_delayover 3650 days: the follow-up may never fire.
Complete example
A two-event bundle: a standalone event whose first option schedules a follow-up. It validates and renders as is.
File release.yaml:
code: drifting_museum
name: The Drifting Museum
month: '2026-10'
status: draft
notes: Example bundle from the Forge World contract
File events/accession_notice.yaml:
slug: accession_notice
kind: standalone
name: Accession Notice
interaction_events:
- role: main
title: Accession Notice
description: >-
A courier drone delivers a museum receipt for our capital's central plaza,
"donated" twelve years from now. The signature is the current governor's.
picture_hint: GFX_evt_ancient_databank
options:
- opt_key: A
text: Investigate the receipt.
effects:
- category: resource_gain_scaled
resource: energy
percent_of_stockpile: -0.05
min_amount: -300
max_amount: -25
- category: trigger_event
event_key: accession_notice_followup/main
days_delay: 90
- opt_key: B
text: File it with the other impossible paperwork.
effects:
- category: modifier_add
modifier_name: filed_and_forgotten
modifier_description: An unexplained receipt sits in the archive, unread.
modifier_stat: country_unity_produces_mult
modifier_value: 0.05
duration_days: 360
File events/accession_notice_followup.yaml:
slug: accession_notice_followup
kind: standalone
name: Provenance
default_trigger_type: triggered_only
interaction_events:
- role: main
title: Provenance
description: >-
The courier's flight log leads to a museum station adrift at the edge of our
space. Its curators have already prepared a plaque with our name on it.
options:
- opt_key: A
text: Accept the plaque.
effects:
- category: add_artifacts
amount: 2
- category: research_progress
tech_area: society
progress: 0.10