# Gum Runtime Syntax Version

> The integer version stamped on Gum runtime assemblies via GumSyntaxVersionAttribute, used by the tool's codegen to gate emitted code. Triggers when bumping the runtime syntax version, touching AssemblyAttributes.cs in GumCommon/MonoGameGum/RaylibGum/SkiaGum, or changing SyntaxVersionDetectionService.

- Skill: `vchelaru/gum-runtime-syntax-version` (Agent Skill)
- Install (CLI): `npx skillmds@latest add vchelaru/gum-runtime-syntax-version`
- Raw SKILL.md: https://api.skillmd.com/api/skills/vchelaru/gum-runtime-syntax-version/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: vchelaru (https://skillmd.com/u/vchelaru)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/vchelaru/gum-runtime-syntax-version

---


# Gum Runtime Syntax Version

Not the same thing as `.gumx` file format versioning (see `gum-project-versioning`). This is an **assembly-level** integer stamped on each runtime DLL that tells the Gum tool's codegen which conventions / namespaces / role interfaces the consumer's runtime supports.

## Where it lives

- Attribute type: `GumDataTypes/GumSyntaxVersionAttribute.cs`.
- Stamped via `AssemblyAttributes.cs` in each runtime project:
  - `GumCommon/AssemblyAttributes.cs`
  - `MonoGameGum/AssemblyAttributes.cs` (KniGum and FnaGum csprojs glob `..\**\*.cs`, so they inherit this stamp automatically)
  - `Runtimes/RaylibGum/AssemblyAttributes.cs`
  - `Runtimes/SkiaGum/AssemblyAttributes.cs`
- Detection (tool side): `Tools/Gum.ProjectServices/CodeGeneration/SyntaxVersionDetectionService.cs`.
- Public docs / version table (the version history lives here, not in this skill):
  `docs/gum-tool/upgrading/syntax-versions.md` — published at
  https://docs.flatredball.com/gum/gum-tool/upgrading/syntax-versions

## How detection works

Reads the consumer's `.csproj`:
1. If `ProjectReference` → finds `MonoGameGum`/`RaylibGum`/`SkiaGum`/`KniGum`/`FnaGum`, opens that project's `AssemblyAttributes.cs`, regex-parses the version.
2. Else if `PackageReference` → locates the DLL in the NuGet cache, reads the attribute via `MetadataLoadContext`.
3. Else manual override from `.codsj`'s `SyntaxVersion` field.

**GumCommon is not on the detection scan list** — stamping it is for assembly-metadata consistency, not for codegen detection.

## When to bump

When the runtime surface that codegen cares about changes in a way that requires the tool to emit different code (renamed/removed role interfaces, new runtime types, namespace changes). Bump all four assemblies in lock step and add a row to the version table.

## Gate on a safe floor, not the exact release that added the API

A codegen check like `context.ResolvedSyntaxVersion >= N` doesn't need to match the version that
introduced the target API — it only needs to guarantee the API exists. If an API shipped mid-cycle
inside an already-stamped version (so some assemblies at that version have it and some don't), gate
on the *next* bumped version instead. The cost is early adopters keep seeing the old code path a
little longer; the alternative — gating loosely to minimize that — risks emitting code that fails to
compile against older runtimes still reporting that version. See `AddFindByNameAssignment` in
`CodeGenerator.cs`, which gates `FindFormsControl<T>` on `ResolvedSyntaxVersion >= 1` even though the
method shipped mid-version-0.

## When NOT to bump

Pure renderable / Forms / sample changes that the codegen doesn't pattern-match against. The version is for **codegen gates**, not a general changelog.

## Instance-Member Pattern vs Extension-Method Shims

When migrating a static extension to an instance method on `GraphicalUiElement` (or another GumCommon type), the instance method **entirely eliminates** the need for namespace-migration shims:

- Extension methods require a `using` directive in scope; instance methods need nothing.
- Two extensions with identical signatures cause CS0121 ambiguity when both namespaces are imported — instance methods sidestep this entirely (they always win over extensions).
- No `[Obsolete]` spam: the old extension is deleted; call sites resolve to the instance method automatically.

This pattern is viable wherever a GumCommon seam (like `IGumService.Default`) can dispatch the work. Applied to `AddToRoot` / `RemoveFromRoot` at syntax version 3: the per-platform extension classes were deleted and the instance methods dispatch via `IGumService.Default`. See issue #3119.

