Skip to main content
Most WG content rows aren’t static text. They describe what they do to a character, and that description is a list of operations on the row’s operations column. When the character sheet builds, it walks every operation attached to every selected feat / ancestry / class / item / spell and applies them to a variables store. This page is the canonical reference for every operation type. The TypeScript schemas live in frontend/src/schemas/operations.ts; this page mirrors them in prose.

The shape

Every operation looks like this:
id is required by the engine for deduplication and result tracking. Never reuse one across operations.

Variables, briefly

Most operations read or write a variable (proficiencies, attributes, HP, perception, resistances, etc.). The set of named variables is defined in frontend/src/process/variables/variable-manager.ts, there are ~166 of them. Each variable has a type: When writing operations, always look up similar existing content first and copy the exact variable name and value shape. The engine fails silently on unknown variable names.

Variable operations

These read and write the variable store. Most operations on a typical feat or ancestry are these.

createValue

Introduce a new named variable on the character. Used for variables that aren’t in the default set (custom counters, archetype-specific bookkeeping).
If the variable already exists, this is a no-op.

setValue

Hard-set a variable. Wins over any prior value, including setValues from other content (last-write-wins).
Use sparingly: it stomps any other contribution. Prefer adjValue or addBonusToValue when stacking matters.

adjValue

Adjust a value. The exact behaviour depends on the variable type:
  • num: additive (+1, -2). Stacks with other adjValues on the same variable.
  • prof: increase a proficiency rank ('U' → 'T' → 'E' → 'M' → 'L'). Pass '1' to step up, '-1' to step down.
  • list-str: append. The string is the entry to add (e.g. "fire, 5" for resistances).
  • bool: set to true.
  • str: replace.

addBonusToValue

A typed numeric bonus that respects PF2e bonus stacking rules (item / status / circumstance bonuses don’t stack with the same type). Use this rather than adjValue whenever the source describes a bonus type, and use it (with value: null) for any conditional or narrative note you want to surface beneath a stat without it being a literal numeric bonus. The three fields are value (number, or null for a non-numeric note), type ("item" / "status" / "circumstance" / "" for untyped), and text (free-form rider).

How it renders

WG composes value, type, and text into a single line shown beneath the stat. The shape of that line is what makes this operation feel different from adjValue: That last form is the workhorse for “show this note under the proficiency, but it isn’t a number”. Anything you want a player to see attached to a stat (situational rerolls, success-promotion clauses, “use this instead of normal rules” riders) goes in via value: null + type: "" + the prose in text.

Examples

bindValue

Bind one variable to another’s source so the bound value follows the original. Used for class DC inheritance, casting attribute mirroring, and a few other linked-stat patterns.
storeId is 'CHARACTER' for the active character; companion stores use their own IDs.

Granting and removing content

These attach (or detach) other database rows to the character.

giveAbilityBlock / removeAbilityBlock

Grant or revoke a feat, action, class feature, sense, heritage, mode, or physical feature by id. The type field here is the AbilityBlock subtype, not the row’s database type.
type is one of: 'action' | 'feat' | 'physical-feature' | 'sense' | 'class-feature' | 'heritage' | 'mode'.

giveLanguage / removeLanguage

For a player-chosen language, use a select with optionType: 'LANGUAGE' instead.

giveSpell / removeSpell

Grant or revoke a single spell. giveSpell carries the metadata that determines how it shows up on the sheet (focus pool vs spell slot, casting source, fixed rank for innate spells).

giveSpellSlot

Add spell slots to a casting source. Each slot is { lvl, rank, amt } where lvl is the character level the slot becomes available, rank the spell rank it casts, and amt the count (or null for unlimited / cantrip).

giveItem

Add an item to the character’s starting inventory.

giveTrait

Add a trait to the character itself. Rare; used when an ancestry or archetype literally makes you have a trait (e.g. humanoid).

Branching and choices

conditional

Run nested operations only when conditions match. Conditions check variable state.
Operators: INCLUDES, NOT_INCLUDES, EQUALS, NOT_EQUALS, LESS_THAN, GREATER_THAN, GREATER_THAN_OR_EQUALS, LESS_THAN_OR_EQUALS. Multiple conditions are AND-ed; nest a second conditional inside trueOperations for OR semantics.

select

Player-facing choice. Two modes: Predefined: you list the options inline.
Filtered: you describe a content query and the engine renders all matches.
optionType and the matching filter type must agree. Valid pairs: The chosen option id is recorded on character.operation_data.selections, keyed by the select operation’s id.

Display and meta

These don’t change stats; they affect what the player sees.

injectText

Append prose to another piece of content’s description, conditionally. Used for archetype rewrites that say “instead of X, you can also Y” without forking the source row.

injectSelectOption

Inject a CUSTOM option into another select operation by writing into the engine variable INJECT_SELECT_OPTIONS. Used so an archetype or feat can extend a class’ choice list without rewriting the class.
The value is a stringified InjectedSelectOption, shaped as { opId, option } where opId is the target select operation’s id and option is the new CUSTOM option to add.

sendNotification

Surface a Mantine toast on the sheet, for one-time reminders (“you regained Hero Points”, “your familiar has a new ability available”).

defineCastingSource

Declare a casting source so spell-slot operations and the spell UI know it exists. The class (or archetype) that introduces the source emits this; subsequent giveSpellSlot / giveSpell operations reference its name.
The value shape is <name>:::<tradition>:::<type>:::<attribute>. The engine parses these out when computing spell DCs and slot counts.

See also