Migrates the reaper-king-no-more proof of concept into decks/reaper-king-no-more/
as the first deck under a shared tools/ engine, so the repo can hold many
Commander decks instead of one implicit one.
- tools/deckctx.py: new shared DeckContext, resolves --deck / $MTG_DECK / cwd,
loads a deck's config.yaml, and derives color identity from the commander's
own card data (never a hardcoded color combination).
- cards.py: drop the JUND=frozenset("BRG") constant; jund_legal() renamed to
identity_legal(card, identity); DB() takes an explicit blacklist_path since
the blacklist is per-deck, not shared.
- combos.py, roles.py, similar.py, similar_text.py, bracket_check.py: take
--deck, use the deck's real identity instead of Jund/BRG.
- power.py, card_stats.py, forge_report.py: OURS deck-name constant now comes
from the deck's config (name: / commander), matched via DeckContext instead
of hardcoded "Reaper King No More".
- to_dck.py, batch_run.py, ab_test.py: .dck filename and [metadata] Name= are
derived from the deck (slug / config name), not a hardcoded "reaper.dck".
- generate.py: RECIPES and make_variants.py's VARIANTS (deck-specific
hypotheses) moved out of Python into decks/reaper-king-no-more/variants.yaml;
protected cards now come from config.yaml's protected: list instead of a
hardcoded set.
- New tools/mtg dispatcher: `tools/mtg decks/<name> <tool> [args...]` runs any
tool against any deck without cd-ing into its directory.
- data/ (Scryfall/MTGJSON/Spellbook bulk, ~1.2GB, gitignored) and embeddings.npz
move to the repo root as shared, commander-format-wide data.
- docs/howto.md: moved from the deck dir (it documents the tool, not the deck)
and updated its example commands to the real generalized CLI.
- README.md: rewritten to describe the multi-deck repo and point at
decks/reaper-king-no-more as the reference example.
Verified after the change: bracket_check, combos, and roles against
reaper-king-no-more reproduce the exact PASS/11-combos/role-profile numbers
from before the move; generate.py --list now loads recipes from YAML;
make_variants.py reproduces all 7 hand-curated variants including the
mikaeus FAIL control case; to_dck.py derives the right Name= and filename;
variant.py and compare.py reproduce decks/README.md's original numbers
exactly. The original POC at ~/mtg/reaper-king-no-more is untouched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPKgLYpMR8szWNFXyK1XNu
4.4 KiB
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.