Editor reference — every screen
The walkthrough builds one pack end to end. This page is the reference: what every screen holds, and why.
The window
Section titled “The window”The title bar carries the open pack file and the build stamp of the editor itself — Galactic Heroes Editor — ewt32.ghpack.json [build 2026-09-18 17:15], and DEBUG when it is a debug build. Which build am I looking at should be a reading, not a deduction.
The toolbar is seven buttons:
| Button | What it does |
|---|---|
| New / Open… / Save / Save as… | the .ghpack.json source file — your pack, not the extension |
| Check | run the validator and go to the Check tab |
| Export… | write the extension into the export folder |
| Export into the game | write it straight into extensions/<packid> — asks first, game must be closed |
The status bar is two halves. On the left, what is in this pack and what the host already has: “1 fleet template(s), 1 hero(es) in this pack · 17 fleet(s) and 261 hero(es) already in the game, shown read only.” On the right, the harvest receipt: “6 archetypes · 28 perks · 390 ships · 17 host fleets · 261 host heroes · 1 PROBLEM(S).” Zeroes on the right mean the folders on the Pack tab are wrong.
The eight tabs
Section titled “The eight tabs”| Tab | Authors | Notes |
|---|---|---|
| Pack | the manifest, the text page number and the three folders | covered in the overview |
| Fleets | fleet templates | a ladder, one tier per hero star |
| Heroes | hero templates | covered in the walkthrough |
| Missions | corporation missions | see below |
| Spend plans | what heroes buy, in order | covered in the walkthrough |
| Corporations | companies | not a catalogue entry — see below |
| Check | nothing — it reports | 104 rules, the full list; the same findings are shown on every other tab |
| What was read | nothing — it reports | six screens proving the harvest |
Fleets, Heroes and Corporations share a left-hand shape: a filter box, then In this pack above Already in Galactic Heroes — read only, then Add, Copy into this pack and Remove. Host objects are shown so you can read, filter and copy them; they can never be edited, because an edit to something the host owns would be silently discarded and the host may reshape it in any later version.
Missions and Spend plans list only what the pack itself defines, with Add, Copy and Delete. What the host already declares is on the What was read screens instead — Spend for its eleven plans.
Missions
Section titled “Missions”A corporation mission is paid work a company offers you against a rival it is already fighting. The mod ships six; a pack can add more. See Corporation missions for what they are in game.

| Field | What it decides |
|---|---|
| Mission id | permanent, prefixed, unique against the host’s own six |
| Title | what the player reads in the corporation’s offer list |
| Briefing | the longer text |
| Objective | the one line the game shows while the mission is active |
| Control panel | what the player actually walks up to and uses |
| Reward | base payout in credits |
| Minimum grudge | how many campaigns one company must already have run against the other before this is offered. 0 means “offer it even without a feud.” |
| Mission level | difficulty band |
The control panel list is read out of the game’s own schema — libraries/common.xsd declares them as the controlpaneltypelookup enumeration — not typed into the editor. A patch that adds a panel gives it to the editor with no code change, and a panel that does not exist is an error rather than a mission nobody can finish.
One note rather than an error is worth knowing about: access_* panels only look at something, hack_* panels break it. An access panel with a sabotage-sized reward is a balance choice, not a defect, so the editor says it out loud and lets you keep it. For scale, the core reconnaissance mission pays 90,000.
Corporations are not like the rest
Section titled “Corporations are not like the rest”
Everything else the editor writes is a catalogue entry. The mod wipes its fleet and hero tables on every load and each extension registers into the empty table, so exporting again simply replaces what was there.
A corporation is not that. It owns money, contracts, favours, liabilities, a chronicle and a share register, and all of it lives in the player’s save. So the host’s registration is ensure-exists, and the split matters:
| Field | On a save that already has the company |
|---|---|
| name, bucket, lore, aggression, defence reserve | re-read on every load, so an edit does take effect |
| founding capital | read once, at founding — an edit never tops it up |
There is no way to remove one, either. Uninstalling a pack leaves its corporations in the save, inert but intact, because every contract, grudge, share register and chronicle entry that ever named them would otherwise dangle. The Remove button says so before it does anything.
That permanence is why an id collision is an error here rather than a warning. A colliding fleet id produces a refused registration and a missing fleet, which is annoying. A colliding corporation id produces two packs both believing they own a company that holds money and shares in a live save, and that cannot be repaired afterwards.
The three behaviour knobs
Section titled “The three behaviour knobs”Each defaults to what every corporation in the mod does today, so a company written without touching them behaves exactly like one written before the fields existed.
- Founding capital — the host’s own companies start with 100,000,000. This is the number that decides a takeover: a raider roughly 1.6× richer than its target reaches control, so this field is what says whether a company is predator or prey.
- Aggression (percent, 100 = ordinary) — scales the two budgets that gate whether the company commissions raids and assaults against rivals.
0is a company that trades, bids and defends but never moves against anybody. It changes nothing else. - Defence reserve % (
-1= follow the mod’s global) — the share of its own money it refuses to spend buying back shares when somebody is taking it over.
The What this company will be line at the bottom says what the three add up to in sentences, because three integers do not tell an author that they have just founded somebody’s lunch.
Origin faction is not decoration. Favour accrual, relation gates and market access all key off it, and the host refuses a corporation without one.
What it refuses
Section titled “What it refuses”104 rules: 68 errors, 28 warnings, 8 notes. Errors block export; warnings and notes do not. Every issue says what to do about it, and double-clicking a row on the Check tab jumps to the field it is about.
Where it says it
Section titled “Where it says it”The check runs by itself about a third of a second after any edit, and every finding carries an address — the object, the nested object (a tier, a perk row, a plan step) and the field. That address is used in four places at once:
| Where | What you see |
|---|---|
| the tab header | Heroes ✖ 2 or Fleets ⚠ 1 — the worst kind and the count, so a problem two tabs away is visible |
| the object’s row in the list | the same mark; a perk row, a plan step or a tier is tinted, with the findings as its tool tip |
| above the form | one line per error or warning, message and fix together, five at a time and then a scroll bar; notes are counted underneath and listed on the Check tab |
| the field itself | a red or amber outline on the box that sets it, with the message and the fix as its tool tip |
Fix the field and every mark goes. The Check tab remains the full list, notes included, and its double-click lands on the tab, selects the object and the row, and focuses the field.
One finding is not a rule about the pack but about the screen: text typed into a number box (GH140). WPF keeps the previous number and says nothing; the editor shows the box outlined, names the value the field still holds, and refuses to export until the box holds a number again.
The rules fall into three kinds, and keeping them apart is the point:
1. What the host also enforces — no id, no tiers, a tier with no flagship, no archetype, no faction, a duplicate id. Checking here is not redundant: the host can only refuse, hours later, into a log file the author may never open.
2. What the host cannot enforce. Namespacing above all. Once a save has seen an id it is permanent, and a collision between two guest packs cannot be repaired. The host cannot tell an unprefixed guest id from a core one — the editor knows which pack it is writing.
3. What makes a template good rather than valid — a perk the archetype cannot use, a fleet hung on a station-bound hero that will never upgrade it, a founder name that repeats its own rank. None of these break anything, and all three are defects the core roster itself contains.
| Codes | About |
|---|---|
GH001–GH009 | the pack itself: id, prefix length, display name, registering nothing, version, the text page |
GH010–GH023 | fleet templates: tiers, flagships, escort counts, ship sources |
GH030–GH057 | heroes: ids, group, rank, faction, archetype, fleet, biography, the spend plan it names |
GH060–GH069 | perks on a hero: unknown, duplicated, unreachable, wrong archetype |
GH080–GH096 | corporations: collisions, origin faction, capital, aggression, reserve |
GH100–GH111 | corporation missions: ids, title, objective, panel, reward, grudge |
GH120–GH131 | spend plans: ids, label, steps, a perk step naming nothing or a perk twice, a shares target |
GH140 | text typed into a number box |
GH150 | a brace in a name or a story — X4 reads {…} on a text page as a reference to another entry |
The generator also handles what an author cannot see coming: an apostrophe in a biography would end an MD string literal, a " would end the XML attribute, and -- is illegal inside an XML comment. All three are neutralised at the one place they are written.
What the rules say about the host
Section titled “What the rules say about the host”Pointing the editor’s rules at the mod that taught it those rules costs nothing, and the self-test writes the result to host-audit.txt. Zero errors, and four kinds of warning:
GH047 ×200 | a founder name that repeats its own rank — the game prints “Commodore Commodore Falo” |
GH063 ×16 | a perk whose applies_to does not include the hero’s archetype, so nothing reads its effects |
GH042 ×14 | a coordinator carrying a $fleet_template_id, which fleet_upgrades=false means is never used |
GH021 ×9 | a tier with an escort ship chosen and a count of zero |
The audit also found one thing in the editor rather than the mod: GH017 fired five times on the Xenon fleets, which declare XL_I and XL_K for the I and the K. Those are the host’s own class labels, not typos, and the rule now compares only the size.
What was read
Section titled “What was read”Six screens, and the reason they exist is that an empty list somewhere else in the editor is always a harvest failure, never an empty world. If a dropdown has nothing in it, the answer is here.
Reading — did it read, from where, and how much
Section titled “Reading — did it read, from where, and how much”
Three blocks:
- Problems while reading — anything skipped and why. The line in the shot is a good example of the class: a folder named
extensions_disabled_backup_20260820holds extensions the game does not load from, so reading it would have offered ships that are not really installed. - Where the game loads data from — every archive and folder X4 will read, in load order, with its entry count.
- Counts — the harvest in one block. This is the fastest way to answer “did it see my mod?”
Game — what the installed game provides
Section titled “Game — what the installed game provides”
Every faction the game has, with its source and its tags. claims space is the one to read: it is the game’s own tag for a faction that owns territory. Without it the mod cannot resolve a home sector, and a hero of that faction never spawns. The from column tells you whether a faction came from the base game, a DLC or a mod.
Heroes — what the host declares
Section titled “Heroes — what the host declares”
The archetype table is the most useful thing on this screen, because it is where the differences between the six live:
| Column | Why it matters to a pack |
|---|---|
| commands | fleet, summon_pool, fleet_leaders, subordinates — what the hero actually directs |
| fleet upgrades | off for coordinators and hive lords. Giving one a fleet template is a warning: nothing will ever build it. |
| station bound | the hero does not fly. It also means the hero cannot be hired. |
| Kha’ak only | seeder and hive lord |
| subordinate cap | coordinator 5, hive lord 8; zero for the rest |
Decisions — the two halves, compared
Section titled “Decisions — the two halves, compared”
Two lists describe decisions, they live in different files, and neither one knows about the other — so the editor compares them here.
- Decision kinds — the catalogue: what a decision can be, and which archetypes may take it. A kind is a name and its holders, never behaviour; the behaviour lives in the mod’s decision worker.
- Task kinds — what a faction’s board can ask for, and which archetype works it. A decision is what a hero chooses; a task is what the board offers. An archetype is composed from both.
- Decision sets — what a template offers, with priorities. These are the six the host keeps private, and the ones your exported pack carries as literals.
Two columns repay attention. declared by reads core, or core-no-page for a task type that exists on the board and has no drill-down page in the mod’s Order Board. And the line under the first table — “5 declared kind(s) are set by no set” — is a note, not a fault: the decision worker reaches for some kinds on its own without any set offering them.
Spend — the host’s plans, in order
Section titled “Spend — the host’s plans, in order”
Read-only, and here so a pack author can point a hero at an existing plan instead of writing one.
The closing block is the part worth reading: a hero resolves its plan the way it resolves its fleet — the template’s own spend_plan_id first, the archetype’s default second, nothing third. A hero that resolves to nothing keeps the tier ladder, so a plan is an override, never a requirement.
Live — what the running game is actually deciding
Section titled “Live — what the running game is actually deciding”
The other five screens show what a decision can be. This one shows what is being decided, read out of the running game’s own dump in debug.log. Either can look healthy while the other is wrong, which is the whole reason it is a separate screen.
It needs the game to have written a dump — asked for through the mod’s dev bridge — and the screen says so when there is none, along with the exact log path it is reading. Kinds the game holds that the catalogue does not declare is the row that catches a decision the mod produces and never documented.
Two test lanes
Section titled “Two test lanes”Both must pass before a build is worth shipping, and tools/build.ps1 runs both from the Release binary:
GalacticHeroesEditor.exe --selftest <dir> # headless: harvest, validate, generate, read back; every rule made to fireGalacticHeroesEditor.exe --uitest <file> # opens the real window: 8 tabs, 34 behaviour checksThe self-test walks the validator’s own table of codes and refuses to finish green while a code exists that no case has ever made fire. Measured before that check was written: 86 codes, 23 ever exercised. It also feeds the editor pack files it did not write — nulls, unknown fields, not JSON at all — and the generated text page back through the editor’s own reader.
--uitest exists because a XAML binding is not checked at compile time. A misspelled binding path builds cleanly and shows an empty combo box to someone with no way to know four hundred ships were meant to be in it. WPF reports every one of those, but only to a trace listener nobody attaches. This one attaches, and fails the run. It caught a real crash — RowHeight="Auto", where RowHeight is a double — on its first run.
It has since earned its keep twice more. A reported bug — a group name typed into a hero, gone the moment you left the tab — was reproduced in it before anything was changed, one step per dispatcher tick, so the step that destroyed the value named itself: not typing, not the list rebuild, not saving. Leaving the tab and coming back.
The cause is a trap in WPF rather than in this program, and it is worth knowing if you write WPF: the group box is an editable ComboBox whose Text is bound TwoWay, and whose ItemsSource is a list of suggestions. Clearing that list makes the box reset its Text — and a TwoWay Text writes the empty string straight back over the model. Two rules came out of it: a suggestion list feeding an editable control is append-only, and nothing may be selected while the whole vocabulary is replaced.
A second WPF trap, found on 2026-09-21 and worth knowing for the same reason: the UI lane could not fail the build. It ended with Application.Shutdown(1), and a WPF app’s generated Main is void — it discards what Run() returns — so the process exited 0 whatever the lane found, and the build script read every UI failure as a pass. It exits through Environment.Exit now, the script also reads the verdict the lane prints, and --uitest-fail provokes a red on demand to prove the path carries one. Nothing green before that date was evidence about the UI lane.
Related
Section titled “Related”- Editor overview · Walkthrough
- Order Board — where task kinds end up
- Corporations · Corporation missions