A deckbuilder for the commander format of Magic: The Gathering
Find a file
2025-08-25 09:49:30 -07:00
.github/workflows feat(owned-cards): add owned-only workflow, multi-file parsing, and recommendations export\n\n- Prompt to use only owned cards (gated by presence of lists)\n- Support .txt/.csv owned lists, multi-select; commander exempt\n- Owned-only filtering + add guard; recommendations CSV/TXT when incomplete\n- CSV Owned column when not owned-only\n- Docs and Docker updated (owned_cards + config mounts)\n- CI: Windows EXE on tag; Docker Hub tag fix (no major.minor)\n- Changelog added; RELEASE_NOTES.md ignored 2025-08-25 09:48:05 -07:00
code feat(owned-cards): add owned-only workflow, multi-file parsing, and recommendations export\n\n- Prompt to use only owned cards (gated by presence of lists)\n- Support .txt/.csv owned lists, multi-select; commander exempt\n- Owned-only filtering + add guard; recommendations CSV/TXT when incomplete\n- CSV Owned column when not owned-only\n- Docs and Docker updated (owned_cards + config mounts)\n- CI: Windows EXE on tag; Docker Hub tag fix (no major.minor)\n- Changelog added; RELEASE_NOTES.md ignored 2025-08-25 09:48:05 -07:00
config Release v1.1.1: headless README flags + DockerHub notes auto from template 2025-08-22 16:46:44 -07:00
.dockerignore Fixed an issue with files uploaded to dockerhub, causing it to include some csv and text files that don't need to be there 2025-08-21 11:50:27 -07:00
.env.example Release v1.1.0: headless runner + tagging updates (Discard Matters, Freerunning, Craft, Spree, Explore/Map, Rad, Energy/Resource Engine, Spawn/Scion) 2025-08-22 16:32:39 -07:00
.gitignore feat(owned-cards): add owned-only workflow, multi-file parsing, and recommendations export\n\n- Prompt to use only owned cards (gated by presence of lists)\n- Support .txt/.csv owned lists, multi-select; commander exempt\n- Owned-only filtering + add guard; recommendations CSV/TXT when incomplete\n- CSV Owned column when not owned-only\n- Docs and Docker updated (owned_cards + config mounts)\n- CI: Windows EXE on tag; Docker Hub tag fix (no major.minor)\n- Changelog added; RELEASE_NOTES.md ignored 2025-08-25 09:48:05 -07:00
CHANGELOG.md feat(owned-cards): add owned-only workflow, multi-file parsing, and recommendations export\n\n- Prompt to use only owned cards (gated by presence of lists)\n- Support .txt/.csv owned lists, multi-select; commander exempt\n- Owned-only filtering + add guard; recommendations CSV/TXT when incomplete\n- CSV Owned column when not owned-only\n- Docs and Docker updated (owned_cards + config mounts)\n- CI: Windows EXE on tag; Docker Hub tag fix (no major.minor)\n- Changelog added; RELEASE_NOTES.md ignored 2025-08-25 09:48:05 -07:00
docker-compose.yml feat(owned-cards): add owned-only workflow, multi-file parsing, and recommendations export\n\n- Prompt to use only owned cards (gated by presence of lists)\n- Support .txt/.csv owned lists, multi-select; commander exempt\n- Owned-only filtering + add guard; recommendations CSV/TXT when incomplete\n- CSV Owned column when not owned-only\n- Docs and Docker updated (owned_cards + config mounts)\n- CI: Windows EXE on tag; Docker Hub tag fix (no major.minor)\n- Changelog added; RELEASE_NOTES.md ignored 2025-08-25 09:48:05 -07:00
DOCKER.md feat(owned-cards): add owned-only workflow, multi-file parsing, and recommendations export\n\n- Prompt to use only owned cards (gated by presence of lists)\n- Support .txt/.csv owned lists, multi-select; commander exempt\n- Owned-only filtering + add guard; recommendations CSV/TXT when incomplete\n- CSV Owned column when not owned-only\n- Docs and Docker updated (owned_cards + config mounts)\n- CI: Windows EXE on tag; Docker Hub tag fix (no major.minor)\n- Changelog added; RELEASE_NOTES.md ignored 2025-08-25 09:48:05 -07:00
Dockerfile feat(owned-cards): add owned-only workflow, multi-file parsing, and recommendations export\n\n- Prompt to use only owned cards (gated by presence of lists)\n- Support .txt/.csv owned lists, multi-select; commander exempt\n- Owned-only filtering + add guard; recommendations CSV/TXT when incomplete\n- CSV Owned column when not owned-only\n- Docs and Docker updated (owned_cards + config mounts)\n- CI: Windows EXE on tag; Docker Hub tag fix (no major.minor)\n- Changelog added; RELEASE_NOTES.md ignored 2025-08-25 09:48:05 -07:00
LICENSE Removed references to an old card_info script I had originally thought to include. 2025-01-21 09:26:36 -08:00
mypy.ini Finished v2 of deck_builder, should be largely functional, but could use refinements. WIll continue to work on it, but largely satisfied with how it works. 2025-01-17 17:04:02 -08:00
pyproject.toml chore(release): v1.1.2 bump, notes/template + README updates, Docker Hub description updater, headless/docs tweaks 2025-08-23 15:29:45 -07:00
README.md feat(owned-cards): add owned-only workflow, multi-file parsing, and recommendations export\n\n- Prompt to use only owned cards (gated by presence of lists)\n- Support .txt/.csv owned lists, multi-select; commander exempt\n- Owned-only filtering + add guard; recommendations CSV/TXT when incomplete\n- CSV Owned column when not owned-only\n- Docs and Docker updated (owned_cards + config mounts)\n- CI: Windows EXE on tag; Docker Hub tag fix (no major.minor)\n- Changelog added; RELEASE_NOTES.md ignored 2025-08-25 09:48:05 -07:00
RELEASE_NOTES_TEMPLATE.md feat(owned-cards): add owned-only workflow, multi-file parsing, and recommendations export\n\n- Prompt to use only owned cards (gated by presence of lists)\n- Support .txt/.csv owned lists, multi-select; commander exempt\n- Owned-only filtering + add guard; recommendations CSV/TXT when incomplete\n- CSV Owned column when not owned-only\n- Docs and Docker updated (owned_cards + config mounts)\n- CI: Windows EXE on tag; Docker Hub tag fix (no major.minor)\n- Changelog added; RELEASE_NOTES.md ignored 2025-08-25 09:48:05 -07:00
requirements.txt Release v1.1.0: headless runner + tagging updates (Discard Matters, Freerunning, Craft, Spree, Explore/Map, Rad, Energy/Resource Engine, Spawn/Scion) 2025-08-22 16:32:39 -07:00
run-from-dockerhub.bat feat(owned-cards): add owned-only workflow, multi-file parsing, and recommendations export\n\n- Prompt to use only owned cards (gated by presence of lists)\n- Support .txt/.csv owned lists, multi-select; commander exempt\n- Owned-only filtering + add guard; recommendations CSV/TXT when incomplete\n- CSV Owned column when not owned-only\n- Docs and Docker updated (owned_cards + config mounts)\n- CI: Windows EXE on tag; Docker Hub tag fix (no major.minor)\n- Changelog added; RELEASE_NOTES.md ignored 2025-08-25 09:48:05 -07:00
run-from-dockerhub.sh feat(owned-cards): add owned-only workflow, multi-file parsing, and recommendations export\n\n- Prompt to use only owned cards (gated by presence of lists)\n- Support .txt/.csv owned lists, multi-select; commander exempt\n- Owned-only filtering + add guard; recommendations CSV/TXT when incomplete\n- CSV Owned column when not owned-only\n- Docs and Docker updated (owned_cards + config mounts)\n- CI: Windows EXE on tag; Docker Hub tag fix (no major.minor)\n- Changelog added; RELEASE_NOTES.md ignored 2025-08-25 09:48:05 -07:00
WINDOWS_DOCKER_GUIDE.md feat(owned-cards): add owned-only workflow, multi-file parsing, and recommendations export\n\n- Prompt to use only owned cards (gated by presence of lists)\n- Support .txt/.csv owned lists, multi-select; commander exempt\n- Owned-only filtering + add guard; recommendations CSV/TXT when incomplete\n- CSV Owned column when not owned-only\n- Docs and Docker updated (owned_cards + config mounts)\n- CI: Windows EXE on tag; Docker Hub tag fix (no major.minor)\n- Changelog added; RELEASE_NOTES.md ignored 2025-08-25 09:48:05 -07:00

# 🃏 MTG Python Deckbuilder

License: MIT Python 3.11+ Docker

A fast, menu-driven CLI to build MTG Commander/EDH decks. Supports interactive and headless runs, CSV/TXT exports, owned-card libraries, and Docker.

🔹 Features

  • Commander search with smart theme tagging (primary/secondary/tertiary)
  • Power bracket selection and ideal count prompts
  • CSV and TXT exports with stable filenames
  • Headless mode (non-interactive) and a headless submenu in the main menu
  • Config precedence: CLI > env > JSON > defaults

Highlights

  • Smart tagging and suggestions for commander + themes
  • Exports CSV and TXT decklists to deck_files/
  • Owned-cards mode: point to one or more .txt/.csv files in owned_cards/ and choose "Use only owned cards?"
  • If you opt out, final CSV marks owned cards with an Owned column
  • Interactive menu with a headless submenu
  • Works locally or in Docker (Windows PowerShell friendly)

🚀 Quick start

Docker Hub (PowerShell)

docker run -it --rm `
  -v "${PWD}/deck_files:/app/deck_files" `
  -v "${PWD}/logs:/app/logs" `
  -v "${PWD}/csv_files:/app/csv_files" `
  -v "${PWD}/owned_cards:/app/owned_cards" `
  -v "${PWD}/config:/app/config" `
  mwisnowski/mtg-python-deckbuilder:latest

From source

pip install -r requirements.txt
python code/main.py

From this repo with Docker Compose (PowerShell)

docker compose build
docker compose run --rm mtg-deckbuilder

🤖 Headless mode (no prompts)

  • Auto-headless: set DECK_MODE=headless
    • Example (PowerShell):
      docker compose run --rm -e DECK_MODE=headless mtg-deckbuilder
      
  • Use a JSON config: mount ./config to /app/config and set DECK_CONFIG=/app/config/deck.json
    • Example (PowerShell):
      docker compose run --rm `
        -e DECK_MODE=headless `
        -e DECK_CONFIG=/app/config/deck.json `
        mtg-deckbuilder
      
  • Override via env vars (subset): DECK_COMMANDER, DECK_PRIMARY_CHOICE, DECK_SECONDARY_CHOICE, DECK_TERTIARY_CHOICE, DECK_ADD_LANDS, DECK_FETCH_COUNT, DECK_BRACKET_LEVEL
    • Precedence: CLI > env > JSON > defaults

Headless submenu notes:

  • If one JSON exists in config/, it auto-runs it
  • If multiple exist, theyre listed as "Commander - Theme1, Theme2, Theme3"; deck.json shows as "Default"
  • CSV/TXT are exported as usual; JSON run-config is exported only in interactive runs

Run locally (no Docker)

# Show resolved settings (no run)
python code/headless_runner.py --config config/deck.json --dry-run

# Run with a specific config file
python code/headless_runner.py --config config/deck.json

# Point to a folder; if exactly one config exists, it's auto-used
python code/headless_runner.py --config config

# Override via CLI
python code/headless_runner.py --commander "Pantlaza, Sun-Favored" --primary-choice 2 --secondary-choice 0 --add-lands true --fetch-count 3

CLI flags

  • --config Path to JSON config file or a folder to discover configs (uses DECK_CONFIG by default)
  • --commander Commander name to search and select
  • --primary-choice Primary theme index
  • --secondary-choice <n|none> Secondary theme index or omit with "none"
  • --tertiary-choice <n|none> Tertiary theme index or omit with "none"
  • --add-lands Include land building steps (true/false)
  • --fetch-count Requested number of fetch lands
  • --dual-count Requested number of dual lands (optional; not exported)
  • --triple-count Requested number of triple lands (optional; not exported)
  • --utility-count Requested number of utility lands (optional; not exported)
  • --add-creatures Add creatures
  • --add-non-creature-spells Add non-creature spells orchestrator
  • --add-ramp Add ramp (when not using orchestrator)
  • --add-removal Add removal (when not using orchestrator)
  • --add-wipes Add board wipes (when not using orchestrator)
  • --add-card-advantage Add card draw (when not using orchestrator)
  • --add-protection Add protection (when not using orchestrator)
  • --bracket-level <1-5> Power bracket selection (or use DECK_BRACKET_LEVEL)
  • --dry-run Print resolved config and exit

Booleans accept: 1/0, true/false, yes/no, on/off.

JSON export in headless

  • By default, headless runs do not export a JSON run-config to avoid duplicates.
  • Opt-in with:
    $env:HEADLESS_EXPORT_JSON = "1"
    python code/headless_runner.py --config config/deck.json
    
  • Tip: when opting in, prefer using --config instead of a DECK_CONFIG file path to avoid creating both a stem-based JSON and a second explicit-path JSON.

Example JSON (config/deck.json):

{
  "commander": "Pantlaza",
  "bracket_level": 3,
  "primary_choice": 2,
  "secondary_choice": 2,
  "tertiary_choice": 2,
  "add_lands": true,
  "fetch_count": 3,
  "ideal_counts": { "ramp": 10, "lands": 36, "basic_lands": 16, "creatures": 28, "removal": 8, "wipes": 3, "card_advantage": 8, "protection": 3 }
}

Notes: headless honors ideal_counts (leave prompts blank to accept). Only fetch_count is tracked/exported for lands.

🕹️ Usage (interactive)

  1. Start the app (Docker or from source)
  2. Pick Build a New Deck
  3. Search/confirm commander
  4. Pick primary/secondary/tertiary themes (or stop at primary)
  5. Choose power bracket and review ideal counts
  6. Deck builds; CSV/TXT export to deck_files/

⚙️ Environment variables (common)

  • DECK_MODE=headless
  • DECK_CONFIG=/app/config/deck.json
  • DECK_COMMANDER, DECK_PRIMARY_CHOICE, DECK_SECONDARY_CHOICE, DECK_TERTIARY_CHOICE
  • DECK_ADD_LANDS, DECK_FETCH_COUNT
  • DECK_ADD_CREATURES, DECK_ADD_NON_CREATURE_SPELLS, DECK_ADD_RAMP, DECK_ADD_REMOVAL, DECK_ADD_WIPES, DECK_ADD_CARD_ADVANTAGE, DECK_ADD_PROTECTION
  • DECK_BRACKET_LEVEL

Optional name-based tag overrides (mapped to indices for the chosen commander):

  • DECK_PRIMARY_TAG, DECK_SECONDARY_TAG, DECK_TERTIARY_TAG

📁 Folders

  • deck_files/ — CSV/TXT exports
  • csv_files/ — card data
  • logs/ — logs
  • config/ — JSON configs (optional)
  • owned_cards/ — your owned cards lists (.txt/.csv); used for owned-only builds and Owned flagging

🧰 Troubleshooting

  • Use docker compose run --rm (not up) for interactive sessions
  • Ensure volumes are mounted so files persist (deck_files, logs, csv_files)
  • For headless with config, mount ./config:/app/config and set DECK_CONFIG
  • Card data refresh: if csv_files/cards.csv is missing or older than 7 days, the app refreshes data and re-tags automatically. A .tagging_complete.json file in csv_files/ indicates tagging completion.

📦 Releases

  • Release notes are maintained in RELEASE_NOTES_TEMPLATE.md. Automated workflows read from this file to populate Docker Hub and GitHub releases.

🧩 Owned cards library

  • Place .txt or .csv lists in owned_cards/ (one card name per line for .txt; any .csv with a name column works).
  • After commander selection, youll be prompted: "Use only owned cards?"
    • Yes: deck builds from owned cards only; if fewer than 100 cards, it stays incomplete and prints a note.
    • No: the build uses the full pool, but the final CSV marks owned cards with an Owned column.
  • If an owned-only build is incomplete, a recommendations file is exported: deck_files/[stem]_recommendations.csv and .txt. The app prints: "Recommended but unowned cards in deck_files/[stem]_recommendations.csv".

📄 License & help

  • License: MIT (see LICENSE)
  • Issues/Requests: GitHub Issues/Discussions
  • Docker details: see DOCKER.md