mark's magic decks
Find a file
2026-09-12 00:41:47 -04:00
decks/reaper-king-no-more Use new extension 2026-09-12 00:41:47 -04:00
docs Restructure into a multi-deck engine; generalize tools/ off Jund/Reaper hardcodes 2026-09-12 00:37:42 -04:00
tools Use new extension 2026-09-12 00:41:47 -04:00
.gitignore Restructure into a multi-deck engine; generalize tools/ off Jund/Reaper hardcodes 2026-09-12 00:37:42 -04:00
deck.mtg rename to .mtg extension for Forgejo's single-extension matching 2026-09-12 00:38:44 -04:00
LICENSE Initial commit 2026-09-12 04:07:34 +00:00
README.md Restructure into a multi-deck engine; generalize tools/ off Jund/Reaper hardcodes 2026-09-12 00:37:42 -04:00

mtg

A generic toolkit for building, testing, and simulating Magic: The Gathering Commander decks — evidenced by real games played in a real rules engine (Forge), not vibes.

Give it four things about a deck — a commander, a card pool, a blacklist of cards you refuse to play, and a few constraints (bracket, land count, role budget) — and it derives everything else from offline card databases: color identity, legality, Game Changers, Scryfall Tagger tags (so it knows what a "sac outlet" or "drain payoff" is), and the Commander Spellbook combo database (108k+ combos). It can then generate deck variants as falsifiable hypotheses, check them against Commander Bracket rules and house rules, and simulate them in Forge to get card-level and deck-level statistics — cast rate, win-rate contribution, synergy pairs — instead of guesses.

See docs/howto.md for the full methodology: what you supply, how pool size and game count determine whether results mean anything, how the Forge AI's weaknesses get worked around, and how to read the output honestly.

Layout

mtg/
  tools/                      generic engine — works on ANY deck given its config.yaml
    mtg                         single dispatcher: tools/mtg decks/<name> <tool> [args...]
    deckctx.py                  resolves --deck / $MTG_DECK, loads config.yaml
    cards.py                    shared index: oracle + tags + edhrecRank + combos + blacklist
    bracket_check.py            Bracket 3 + house-rule check (game changers, MLD, vacuum combos)
    combos.py                   offline combo finder (included / one-card-away)
    roles.py                    role classification + budget profile
    generate.py                 role-budget variant generator (recipes in <deck>/variants.yaml)
    make_variants.py            hand-curated cut/add variant generator (same file)
    to_dck.py                   decklist -> Forge .dck
    batch_run.py / run_forge.sh / ab_test.py    Forge simulation, in bulk or A/B
    forge_report.py / card_stats.py / power.py  turn Forge logs into reports
    compare.py                   rebuilds a deck's decks/README.md summary table
    similar.py / similar_text.py / embed.py     semantic "cards like this" search
    fetch_data.py                downloads the shared bulk data below

  decks/
    reaper-king-no-more/       one deck: data + config, the reference example
      config.yaml               commander, pool, constraints, role budget, protected cards
      decklist.txt               the 100 cards
      blacklist.txt              cards you refuse to play, with reasons
      variants.yaml              variant hypotheses (role-budget recipes + hand-curated cut/add)
      plan.md / README.md        this deck's own design notes
      forge-overrides/           AI tuning for cards Forge's default AI can't pilot
      sim_substitutions.yaml     simulation-only stand-ins for AI-unpilotable cards
      decks/<variant>/           RESULTS: one dir per archetype variant (generated)

  data/                       gitignored, ~1.2GB — Scryfall/MTGJSON/Spellbook bulk downloads.
                               Shared across every deck: this is Commander-format-wide data,
                               not deck-specific. One copy at the repo root.
  out/                       gitignored scratch output
  docs/howto.md              the full methodology (pool size, game count, AI tuning, caveats)

Quickstart

# one-time, shared across all decks
python3 tools/fetch_data.py            # ~1.2GB: Scryfall, MTGJSON, Spellbook
python3 tools/embed.py                 # -> data/embeddings.npz
# install Forge 2.0.14 to ~/forge (needs Java 17+)

# check the reference deck
python3 tools/bracket_check.py --deck decks/reaper-king-no-more
python3 tools/combos.py --deck decks/reaper-king-no-more
python3 tools/roles.py --deck decks/reaper-king-no-more

# or via the single dispatcher
tools/mtg decks/reaper-king-no-more bracket_check
tools/mtg decks/reaper-king-no-more variant no-mikaeus --sim 24

To add a new deck: copy the shape of decks/reaper-king-no-more/ (at minimum config.yaml, decklist.txt, blacklist.txt), point --deck at it, and every tool in tools/ works on it immediately — nothing in tools/ is hardcoded to a specific commander, color identity, or deck name. See docs/howto.md for what each config field does and why, and decks/reaper-king-no-more/plan.md / README.md for a worked example of building one deck end to end.