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 infrontend/src/process/variables/variable-manager.ts, there are ~166 of them. Each variable has a type:
| Type | Examples |
|---|---|
num | MAX_HEALTH, SPEED, FOCUS_POINTS |
str | SIZE, CASTING_SOURCES |
bool | USE_PIERCING_DAMAGE_RESISTANCES, DUAL_CLASS |
prof | SKILL_ATHLETICS, SAVE_FORT, WEAPON_SIMPLE |
attr | ATTRIBUTE_STR, ATTRIBUTE_DEX |
list-str | RESISTANCES, WEAKNESSES, IMMUNITIES, LANGUAGES, SENSES |
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).
setValue
Hard-set a variable. Wins over any prior value, including setValues from other content (last-write-wins).
adjValue or addBonusToValue when stacking matters.
adjValue
Adjust a value. The exact behaviour depends on the variable type:
num: additive (+1,-2). Stacks with otheradjValues 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 composesvalue, 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:
value | type | text | Renders as |
|---|---|---|---|
1 | "item" | "" | +1 item bonus |
1 | "circumstance" | "to Climb trees" | +1 circumstance bonus to Climb trees |
null | "" | "If you get a success, you get a critical success instead." | If you get a success, you get a critical success instead. |
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
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.
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.
optionType and the matching filter type must agree. Valid pairs:
optionType | Filter type | What the player picks |
|---|---|---|
CUSTOM | (none, predefined only) | One of your inline operations blocks |
ABILITY_BLOCK | ABILITY_BLOCK | A feat / action / etc. |
SPELL | SPELL | A spell (for grant) |
LANGUAGE | LANGUAGE | A language |
TRAIT | TRAIT | A trait |
ADJ_VALUE | ADJ_VALUE | A skill / weapon group / armor group to bump |
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.
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.
value shape is <name>:::<tradition>:::<type>:::<attribute>. The engine parses these out when computing spell DCs and slot counts.
See also
- Content Data: the data layer these operations live on.
frontend/src/schemas/operations.ts: Zod schemas, source of truth.frontend/src/process/variables/variable-manager.ts: full list of named variables./create-spell,/create-ability-block, and the rest of thecreate-*endpoints: how operations get persisted via the public API.

