Skip to content

0012: File structure and tag roster ​

Status: Accepted. Amends decisions 0009, 0010, and 0011.

Context ​

The prototype writes one file per match: a match header (version, recorder, players, format, deck, score) followed by shorter game headers. PGN has no concept of a match. A PGN file is "a sequential collection of zero or more PGN games", and every game carries its own complete tag pair section, starting with the Seven Tag Roster. Any game can be extracted from a PGN file, or many combined into one, and each stays valid on its own.

.mtgr aims to stay as close to PGN as realistically possible (CONTRIBUTING.md, design principle 7).

Decision ​

File structure ​

  1. The game is the unit. Every game is a self-contained record: a complete tag pair section followed by the game's content. There is no match header.
  2. A file holds one or more games. A recorder normally writes one file per match, holding every game of that match. A file holding a single game, or games from several matches, is equally valid.
  3. Games from the same match share a Match tag value and are numbered by the Game tag. Match-level facts (the match score, sideboarding between games) are derived from the games sharing a Match value; nothing is stored only at match level.

Tag roster ​

  1. Every game has these tags, in this order, before any other tags:

    TagMeaning
    MtgrFormat version, for example "0.3.0". First, so a parser knows the version before reading anything else.
    EventDescriptive event name, for example "Modern League", "Modern Challenge 64", "Casual". ? if unknown.
    SiteWhere the game was played: a client such as "MTGO" or "Arena", or a venue and location for paper. ? if unknown.
    DateStart date of the game, YYYY.MM.DD, with ? for unknown digits.
    RoundTournament round. - where rounds do not apply (leagues, casual play); ? if unknown; multipart values such as 3.1 allowed.
    Player1First player in the match's fixed seat order.
    Player2Second player in the match's fixed seat order.
    Result1-0 (Player1 won), 0-1 (Player2 won), 1/2-1/2 (draw), or * (unfinished, abandoned, or unknown).
    FormatGame format, for example "Modern". ? if unknown.
    MatchIdentifier shared by every game of the same match.
    GameGame number within the match, starting at 1.
    PerspectiveThe player whose seat the game is recorded from (decision 0001). Must equal Player1 or Player2.
  2. Seat order is fixed for the whole match. Player1 and Player2 do not swap between games. Who plays first in each game is recorded in the game (decision 0010), not in the player tags.

  3. Other tags follow the roster. PGN supplemental tags are used where they fit: UTCDate and UTCTime for the start time in UTC, Termination for why the game ended, Annotator for who annotated it. For online sites with no meaningful local time, Date is the UTC date.

  4. Tag names follow PGN: letters, digits, and underscore only, and no tag name appears twice in a game. Extension tag names therefore use an underscore after the prefix (for example MTGO_Version), not a colon.

Amendments ​

  • Decision 0009, item 2 (header times are absolute ISO 8601 UTC) is replaced by PGN's Date, UTCDate, and UTCTime tags.
  • Decision 0010, item 1 (a match is a match header followed by games) is replaced by items 1 to 3 above. Per-game decklists and the rest of 0010 stand.
  • Decision 0011, item 1: extension tag names use PREFIX_Name. The prefix: form remains for values that are not tag names, such as source card IDs (mtgo:19683).

Rules basis ​

The Comprehensive Rules (effective 2026-09-25) do not cover file formats; this decision is a format choice.

PGN basis, checked against "Standard: Portable Game Notation Specification and Implementation Guide" (Steven J. Edwards, 1994), https://www.saremba.de/chessgml/standards/pgn/pgn-complete.htm:

  • Section 8: "A PGN database file is a sequential collection of zero or more PGN games", each with a tag pair section and a movetext section.
  • Section 8.1: tag names are "composed exclusively of letters, digits, and the underscore character", and "the same tag name should not appear more than once in a tag pair section".
  • Section 8.1.1: the Seven Tag Roster (Event, Site, Date, Round, White, Black, Result) is mandatory for archival storage, in a fixed order, before any other tags.
  • Sections 8.1.1.1 to 8.1.1.7: ? for unknown values; Date as YYYY.MM.DD with ? for unknown digits; Round as - where inappropriate and multipart values such as 3.1; Result as 1-0, 0-1, 1/2-1/2, or *.
  • Sections 9.5.2, 9.5.3: UTCTime and UTCDate give the start time and date in UTC.
  • Section 9.8.1: Termination "describes the reason for the conclusion of the game". Magic termination values are defined in the spec (decision 0010), reusing PGN's values (such as abandoned, time forfeit, unterminated) where they apply.

Alternatives rejected ​

  • A match header with short game headers (the prototype). Rejected: a game cannot be extracted on its own, and match-level data can disagree with the games.
  • One file per game. Rejected: sharing a match would mean uploading several files. PGN allows many games per file, and recorders naturally produce a match at a time.
  • White / Black tags. Rejected: Magic has no colours, and who plays first changes between games.
  • A single Players tag listing both names (the prototype). Rejected: PGN uses one tag per side, and Result needs a fixed first and second player to be meaningful.
  • Mtgr after the roster, as PGN export ordering would put it. Rejected: a parser needs the version before interpreting anything else.

Consequences ​

  • The prototype tags map as follows: Mtgr stays (first); Players becomes Player1 / Player2; Local becomes Perspective; Winner and Score become Result per game; Started becomes Date, UTCDate, UTCTime; Match stays; MatchId, GameId, MtgoVersion, SdkVersion, FormatCode become MTGO_-prefixed tags; Recorder, DeckId, DeckName, Clock, Complete, Issue, ResultFrom are redefined in the spec or by their own decisions.
  • The spec must define the order of tags beyond the roster, and the Magic Termination values.