Authoring with Ledger
Ledger is a deterministic gameplay ability system: the rules of a game (its stats, abilities, effects, kinds) are content in .ledger files, the game's C# hosts a world that runs them, and .play files say what the content does, step by step, and are checked. A game made by ledger new GAME [--turns] [--space plane|own] builds, checks and plays at once; start there, and change it (environment.md says where ledger new is).
The loop
Each step answers one question. Run them in this order after any change, and stop at the first that fails.
| Step | What it answers | How |
|---|---|---|
| Edit | content\*.ledger and its .play; one kind's request changes that kind (scope.md) | |
ledger check | Does the content load, and do the plays read? Each error at its file, line and column | ledger check content\GAME.catalog content\GAME.play |
ledger play | Does the content do what the plays say? Each failing step at its line; given several files, one that doesn't load says why and the rest play | ledger play content\GAME.play |
| The headless runner | Does the game around the content still work: a run, a recording replayed, a quickload's round trip? | tools\GAME.Headless: check, run --seed N --quit-at T, record, replay FILE, roundtrip, perf |
| The editor | Does it look and feel right? The dock lists errors, runs plays and shows a pool's pipeline; the inspector reads the running game | Godot, with the ledger addon the build copies in |
ledger is the kernel's tools\Ledger.Tool (environment.md says where it is built and how to run it). ledger check reports every error a catalog has, not only the first, and a definition that names a failed one says it depends on it. ledger check --json and ledger play --json give the same lines as JSON, one object a line, each with a stable id, the line as written and a fix where one is known: read those from a script or as an agent, and the text form, file(line,col): error: problem, by eye. A failing play step quotes its statement under it.
An author's question, and the tool that answers it
| You want to know | Ask |
|---|---|
| How a mechanic is written (a burn, a windup, a channel, an aura, a turn's start, a card drawn and played) | the cookbook's index, the kernel's content\cookbook\README.md: a recipe a mechanic, each loading alone with its play; look there before forms.md |
| How to write a build's affixes and resistances, by damage type | the cookbook's backbone, content\cookbook\backbone.ledger: an affix is a modifier on a stat by type (Damage.Fire + 20%, Resist + 0.25), and one rule a stage reads it bare in its scale (scale 1 - holder.Resist), each portion of a hit meeting its own type's member; two increases sum, as an ARPG's do, and the pipeline lists one rule however many affixes a build holds. It costs little and allocates nothing: a strike through it took 2.6 to 3.3 µs at no affixes, against 2.2 to 2.3 through a rule each; 3.4 to 3.5 against 5.1 at 10; 6.1 to 6.3 against 13.4 to 13.7 at 40; 0 bytes either way. A hit of a parent type alone (deal 40 Elemental, where the portions declare Elemental.Fire) is a change in no portions, so a bare read gives the stat's declared default |
| How a form is spelled, and what it means | ledger forms FORM (ledger forms deal); ledger forms lists them all |
| Every form at once, each with an example from committed content | forms.md, the reference the tool writes |
| Whether the language can say a rule at all, or it is a known debt | traps.md: each refused or quiet trap, and the way round it |
| Why a play's step came out as it did | ledger play --journal LINE content\GAME.play: that play, each step with the journal rows it made |
| Whether the content loads | ledger check content\GAME.catalog |
| Every error at once, each with its id and a fix where one is known | ledger check --json content\GAME.catalog |
| Whether a change broke the game's own code | the headless runner's check, then run for two seeds |
| Whether a run replays the same | record --seed N, then replay FILE: "the same final save" |
| Whether the quicksave holds everything the game keeps | roundtrip: "saved again at once: the same file", then both played on to one save |
| How fast a tick is | perf |
| What the running game's world holds | the editor's inspector, or a play that makes the same state |
| Every rule a hit on a pool meets, in order: each stage's shields, armours and resistances, what each does to the hit, who holds it, and an archetype missing a layer its like hold | ledger pipeline content\GAME.catalog Health, or the dock's Pipeline tab, each rule a button to its line; in a running game the tab narrows to the inspector's picked actor, each when true or false as it stands |
| Why a value is what it is: a stat's base, each term and the effect that gave it, the strongest of each category, its bounds; a pool's anchor, drift, bounds, bands and next crossing | ledger play --why LINE ACTOR.VALUE content\GAME.play: that play, and at its end the value's receipt; in a running game, the inspector's picked actor's pool or stat, each effect a button to its line |
| Why a change came out as it did: each rule's effect, verb, portion and amount, the hit before and after | ledger play --why LINE ACTOR.POOL content\GAME.play (or ACTOR for every pool): the actor's changes the journal holds, newest first, each with its line items; in a running game, the inspector's changes, each opening its lines |
| Why a cast went off when it did: each stretch of its clock at each rate, the stat's terms and the row at each change, each push and beat, a flight's speed and time, its end, and that it adds up | ledger play --why LINE ACTOR.ABILITY content\GAME.play: that play read a tick at a time, and each activation of the ability the actor began, newest first; in a running game, the inspector's picked actor's ability asked as a stat is. Write --why LINE ACTOR.ABILITY, one word: a space leaves a word over, and is refused naming the form |
| Where a name is defined, and every line that reads or names it | ledger names content\GAME.catalog NAME, or the dock's declared names, each opening its definition and listing its uses, each a button to its line |
| What made a rate, over a batch: what an actor dealt and took, by ability or effect, by whose archetype and by type; what killed it; its casts, by order, rule or auto, their tags and refusals; what healed it, its pools' drift among it; how long each effect held it and with how many stacks; its stats' terms by the actor that gives each | ledger why WHO content\GAME.play: each play a run, the why over all of them for an actor a play names or an archetype; in a running game, the dock's Run tab, the inspector's picked actor since the game began or since Again, each ability and effect a button to its line; a game's headless batch reads each run into Ledger.Checks' WhyRuns as it goes and adds them. On many threads a batch wants the server collector (DOTNET_gcServer=1): the ARPG's field took 28.5 s on 32 threads with the workstation collector and 14.2 s with the server's, its end saves the same |
| What a hit of a type and an amount leaves on an archetype: each rule that met it, at its stage, and what it left, and what it raised (a shield's double cost) | ledger pipeline content\GAME.catalog Health --hit Electric 12 Volt, read from the change's line items on a fresh actor; or the Pipeline tab's Hit, in a running game on the picked actor on a copy of its world |
Where the rest is
- the cookbook: recipes by mechanic, lifted from the lab's six games, each a
.ledgerand its.playthat load alone; and below them the concept pairs ported from v2's cookbook. - words.md: where the words are:
ledger forms, then the nearest example, thendesign\by topic. - forms.md: the reference, every form and word with its spelling, meaning, parts and an example, written by
ledger forms --writeand held to the language by the kernel's gate. - traps.md: what the language can't say yet, each a debt with its refusal and the way round it.
- scope.md: which file holds one kind and which holds rules for all.
- moments.md: moments an author meets that surprise: when an auto fires, a read of an ended actor, a report and its flight.
- visibility.md: the checklist for a game where a side doesn't see everything.
- host.md: what
--turnsand--space ownchange in the game's code: the pause, and the game's own space; and a recording kept across a reload of the content. - state.md: the state a game keeps beside the world, and its quicksave and rebind.
- notes.md: the notes to leave for a change.
- environment.md: building offline, where Godot is, running headless.
- changes.md: what changed for an author, dated, newest last.
From ledger-v3's guide/ledger-author/SKILL.md, last changed 2026-11-02.