# MTG Commander Agent: AI Continuation Handoff

Last updated: June 14, 2026

## 1. Project Goal

Build a collection-aware Commander deck-building agent that:

- Imports one or more ManaBox CSV collection exports.
- Suggests commanders and decks compatible with the owned collection.
- Builds legal 100-card Commander lists at multiple power tiers.
- Prioritizes commander mechanics, game plan, synergy, and relevant combos.
- Does not treat shared creature type as sufficient synergy.
- Shows owned and missing cards by card type.
- Shows card images, prices, explanations, supporting-fit scores, and gameplay plans.
- Exports deck lists, shopping lists, and gameplay guides.

The user cares strongly about broad Commander knowledge across Brackets 2, 3,
4, and cEDH rather than a cEDH-heavy recommender.

## 2. Workspace

Repository:

`/home/miguelcastresana/mtg_agent`

Windows path:

`\\wsl.localhost\Ubuntu-24.04\home\miguelcastresana\mtg_agent`

Runtime:

- Python 3.12
- SQLite
- Standard-library HTTP server
- Node 22 through NVM for Cloudflare tooling
- Docker 29
- Wrangler 4

This directory is not currently a Git repository. Do not assume Git history is
available.

## 3. Current Deployment

Durable Cloudflare Pages overview:

`https://mtg-commander-agent.pages.dev`

Current complete application through Cloudflare Quick Tunnel:

`https://louisville-grab-watched-confidence.trycloudflare.com`

The Quick Tunnel is temporary and works only while both local processes run:

```bash
python3 -m mtg_agent serve --host 0.0.0.0 --port 8765
./cloudflared tunnel --url http://127.0.0.1:8765 --no-autoupdate
```

Cloudflare Containers is the intended permanent deployment. The production
Docker image was built and tested successfully. `wrangler deploy` uploaded the
Worker but the image registry rejected the push because this Cloudflare account
does not have the Workers Paid plan.

Exact Cloudflare API error:

```text
Unauthorized: You do not have access to Cloudflare Containers.
Deploying containers requires the Workers Paid plan.
```

After activating Workers Paid, deploy with:

```bash
source ~/.nvm/nvm.sh
nvm use 22
cd /home/miguelcastresana/mtg_agent
npm install
npx wrangler deploy
```

The expected permanent URL is:

`https://mtg-commander-agent.<workers-subdomain>.workers.dev`

Do not purchase or activate billing without the user's explicit approval.

## 4. Cloudflare Deployment Files

- `Dockerfile`: Python 3.12 image containing the app and built SQLite database.
- `.dockerignore`: excludes raw data, tests, caches, exports, and local assets.
- `worker/index.js`: Worker proxy to a single shared container instance.
- `wrangler.jsonc`: container, Durable Object, instance type, and observability.
- `package.json` / `package-lock.json`: Wrangler and Containers dependencies.
- `cloudflare-pages/`: durable deployment overview and downloadable handoff.

Container profile:

- Instance type: `basic`
- 1/4 vCPU
- 1 GiB RAM
- 4 GB disk
- Maximum instances: 1
- Idle sleep: 30 minutes
- Application port: 8080

Local image:

`mtg-commander-agent:test`

Image size reported by Docker: approximately 101 MB compressed/layer content.

## 5. Application Architecture

### Entry points

- `mtg_agent/cli.py`: CLI command definitions.
- `mtg_agent/web.py`: HTML/CSS/JavaScript UI and HTTP API.
- `mtg_agent/recommender.py`: complete deck construction.
- `mtg_agent/discovery.py`: collection-to-commander opportunity ranking.

### Core modules

- `mtg_agent/db.py`: SQLite schema, card queries, corpus signals, card media.
- `mtg_agent/tiers.py`: power profiles and per-source tier weighting.
- `mtg_agent/strategy.py`: card mechanics, gameplay plan, explanations.
- `mtg_agent/synergy.py`: mechanical fit, typal rules, typal penalties.
- `mtg_agent/knowledge.py`: learned card-pair interaction graph.
- `mtg_agent/combos.py`: Commander Spellbook combo ingestion and signals.
- `mtg_agent/combo_fit.py`: filters combos against commander archetype.
- `mtg_agent/deck_details.py`: response serialization and downloads.
- `mtg_agent/validator.py`: Commander legality checks.
- `mtg_agent/collection.py`: ManaBox and generic collection CSV parsing.
- `mtg_agent/deck_import.py`: authorized full-deck import and validation.
- `mtg_agent/corpus.py`: MTGJSON and EDHTop16 corpus synchronization.
- `mtg_agent/community_corpus.py`: licensed community dataset and inferred tiers.
- `mtg_agent/topdeck.py`: TopDeck URL/API ingestion.

## 6. Database

Primary database:

`data/processed/mtg.sqlite3`

Current size:

`199,864,320 bytes`

Important tables:

- `cards`
- `card_media`
- `commander_card_stats`
- `corpus_sources`
- `imported_decks`
- `combo_sources`
- `combo_packages`
- `combo_card_signals`
- `card_synergy_edges`
- `knowledge_sources`
- `combo_pool_cache`

The container copies only the built database. Raw Scryfall data is not required
at request time.

## 7. Current Corpus

Current totals displayed by the application:

- Bracket 2: 956 observations
- Bracket 3: 3,226 observations
- Bracket 4: 4,682 observations
- Bracket 5/cEDH: 146,964 observations
- Total: 155,830 observations
- Learned card links: 434,542
- Commander archetypes: 2,001

Sources:

- `mtgjson`: 188 official Commander preconstructed decks.
- `edhtop16`: 145,708 public cEDH tournament observations.
- `edhtop16_topdeck`: 4 downloaded exact tournament lists.
- `local_authorized`: 2 local authorized complete lists.
- `kaggle_edhrec_core`: 768 inferred Core observations.
- `kaggle_edhrec_upgraded`: 3,226 inferred Upgraded observations.
- `kaggle_edhrec_optimized`: 4,682 inferred Optimized observations.
- `kaggle_edhrec_cedh`: 1,252 inferred cEDH observations.

The Kaggle source is the MIT-licensed "EDHREC Top 100 Commanders Decklists"
dataset, updated September 22, 2025. It contains 9,972 real deck observations
across 100 commanders and about 865,000 card placements.

It does not contain owner-declared brackets. The app labels these observations
as inferred and classifies them using:

- Current Scryfall `game_changer` flags.
- Average nonland mana value.
- Nonland tutor count.
- Land density.
- Ratio of cards with mana value 2 or less.

Do not present inferred brackets as user-declared labels.

## 8. Tier Isolation

The original model accidentally normalized weak cEDH evidence back to full
strength in lower tiers. This has been fixed.

Current behavior:

- Core ignores cEDH corpus evidence.
- Upgraded uses only a small cEDH contribution.
- Optimized uses strong high-power evidence.
- cEDH uses tournament evidence at full strength.
- Unrated imported lists do not silently become casual or competitive evidence.
- Community imports can be explicitly labeled `core`, `upgraded`, `optimized`,
  or `cedh`.

Authorized bracket imports:

```bash
python3 -m mtg_agent corpus import \
  --input imports/bracket-2 \
  --name community \
  --bracket core
```

Equivalent bracket values:

- `core`
- `upgraded`
- `optimized`
- `cedh`

## 9. Recommender Behavior

Deck selection uses:

- Commander rules-text mechanics.
- Corpus inclusion evidence weighted by chosen tier.
- Learned commander/card and card/card links.
- Commander Spellbook combos filtered for archetype relevance.
- Required deck roles: lands, ramp, draw, removal, wipes, protection.
- User collection ownership as a small tiebreaker.
- Purchase budget.
- User-selected supporting-fit threshold.

Supporting-fit threshold options:

- 0: Permissive
- 20: Flexible
- 35: Focused
- 50: Strict
- 65: Very strict

Nonland infrastructure cards cannot bypass commander-plan qualification.
Ramp, draw, removal, wipes, and protection must still have archetype,
contextual, or relevant-combo evidence.

Complete-list fallback added June 14, 2026:

- The builder first uses the exact requested supporting-fit threshold.
- If that cannot produce 99 legal library cards, it lowers the threshold in
  controlled steps while retaining the same contextual and archetype evidence
  requirements.
- It never fills remaining nonland slots with unrelated cards, including cards
  from the user's collection.
- If evidence is still too sparse, it returns an explicit insufficient-evidence
  error rather than inventing a complete list.
- The result exposes both requested and effective thresholds.
- A price cap remains hard: the builder still errors rather than exceed budget.

Contextual direct-fit rule added June 14, 2026:

- Learned card-pair/co-occurrence evidence cannot qualify a card.
- Learned links contribute zero points to supporting fit.
- A shared mechanic label or shared rules-text word cannot qualify a card.
- Mechanical evidence is directional: the card must enable, multiply, protect,
  consume, or pay off an actual commander action or resource.
- Combat matching distinguishes an ability a card merely has itself from an
  ability it grants to the commander. A random unblockable or double-strike
  creature does not support a commander combat-damage trigger.
- Combat support is plan-specific: extra combats retrigger attack/damage
  engines, granted double strike adds combat-damage triggers, cheap evasive
  attackers enable commander ninjutsu, and offensive attack triggers support
  attack-trigger doublers. These cases receive distinct explanations.
- For example, Doran-style toughness combat accepts toughness buffs, defender
  attack enablers, and toughness-based interaction, but rejects incidental
  "gain life equal to toughness" text.
- Non-infrastructure cards require tier-matched archetype evidence, a contextual
  commander relationship, or a contextually approved combo.
- Card-pair links are only a small ranking tiebreaker after direct evidence has
  already qualified a card.
- Every selected nonland card requires direct plan evidence. Ownership and price
  are ranking factors only after that requirement is met.
- Lands remain structural mana-base slots.
- Combo packages cannot qualify from graph evidence alone.

Typed Oracle semantics added June 14, 2026:

- `mtg_agent/semantics.py` converts token-related Oracle text into typed
  producers, consumers, supported domains, trigger events, restrictions, and
  conversion outputs.
- Named resources such as Clue, Food, Treasure, and Squirrel remain distinct.
- Permanent domains remain distinct: artifact token, creature token, artifact
  creature token, and land token are not interchangeable.
- The parser respects `nontoken`, tokens created for opponents, and compound
  requirements such as `differently named artifact tokens`.
- A resource consumer only counts when its output advances the plan, such as
  mana, draw, interaction, damage, tutoring, recursion, or further tokens.
  Sacrificing a Clue merely to put counters on an unrelated creature does not
  qualify.
- Explanations describe both sides of the interaction, for example converting
  the commander's Clues into mana or multiplying its Food Golem tokens.
- Combo result validation uses the same typed token domains. Infinite creature
  tokens no longer satisfy an artifact-token combo plan.
- Pure contextual evidence now requires at least 0.70 semantic confidence.
  Lowering the visible fit threshold cannot admit weaker word associations.

Typal behavior:

- Sharing a creature type with the commander does not increase supporting fit.
- If the commander explicitly deploys or rewards a type, actual creatures of
  that type and cards that search, create, accelerate, or strengthen its package
  receive contextual typal fit.
- Merely mentioning or benefiting from the presence of that type is insufficient.
- Off-tribe cards are accepted when mechanics, corpus, or relevant combos
  justify them.

Combo behavior:

- Brackets 2 and 3 do not force combo packages.
- Combo packages must match the commander plan or directly involve the commander.
- Independent combos require a result aligned with the commander plan, direct
  contextual support from at least half their pieces, and evidence for every
  remaining piece. Corpus popularity or card-pair links alone cannot approve one.
- Mandatory draw-the-game loops are rejected.
- Tangential combos are filtered out.

## 10. Web API

### `GET /`

Returns the complete single-page interface.

### `GET /api/search?q=...`

Searches all cards.

### `GET /api/commanders?q=...`

Commander autocomplete.

### `POST /api/build`

Example:

```json
{
  "commander": "Wilhelt, the Rotcleaver",
  "tier": "upgraded",
  "min_supporting_fit": 35,
  "budget": "",
  "collection": ""
}
```

### `POST /api/analyze`

Ranks possible commanders from an imported collection.

### `POST /api/suggestion/build`

Builds a complete list for one collection recommendation.

### `POST /api/collection/merge`

Merges multiple ManaBox CSV files.

## 11. Implemented UI Features

- Multiple ManaBox CSV upload and merge.
- Commander autocomplete with card images.
- Shared tier and fit-threshold controls.
- Separate budget input for analysis and direct building.
- Four large cards per row, EDHREC-like presentation.
- Double-faced card front/back toggles.
- Card prices and missing completion cost.
- Owned/missing split inside each card-type category.
- Supporting-fit score and explanation for every card.
- Learned card-link and combo indicators.
- Gameplay plan, mulligan, early/mid/late game guidance.
- Archetype-matched combo explanations.
- Sticky navigation between multiple deck suggestions.
- Deck, shopping-list, and gameplay-guide downloads.
- Visible B2/B3/B4/cEDH evidence counts and inferred-evidence count.

## 12. Tests and Verification

Current test result:

```text
48 passed
```

Run:

```bash
cd /home/miguelcastresana/mtg_agent
python3 -m pytest -q
```

Container verification already completed:

- Docker image built successfully.
- `GET /` returned HTTP 200.
- Remote title was `MTG Commander Agent`.
- A Wilhelt Bracket 3 build returned a complete legal deck response.
- The same build was verified through the public Cloudflare Tunnel.

Current public-tunnel verification:

- Homepage: HTTP 200.
- Wilhelt build: HTTP 200.
- B3 observations for Wilhelt: 45.
- Known completion estimate at verification time: EUR 302.63.

## 13. Runbook

### Start locally

```bash
cd /home/miguelcastresana/mtg_agent
python3 -m mtg_agent serve --host 0.0.0.0 --port 8765
```

### Start a Quick Tunnel

```bash
cd /home/miguelcastresana/mtg_agent
./cloudflared tunnel \
  --url http://127.0.0.1:8765 \
  --no-autoupdate
```

The Quick Tunnel generates a new random URL each time. Update
`cloudflare-pages/index.html` and `AI_HANDOFF.md`, then redeploy Pages.

### Deploy Pages overview

```bash
source ~/.nvm/nvm.sh
nvm use 22
cd /home/miguelcastresana/mtg_agent
npx wrangler pages deploy cloudflare-pages \
  --project-name mtg-commander-agent
```

### Build and test the container

```bash
docker build -t mtg-commander-agent:test .
docker run --rm -p 18080:8080 mtg-commander-agent:test
```

### Permanent Cloudflare deployment after paid-plan activation

```bash
source ~/.nvm/nvm.sh
nvm use 22
npm install
npx wrangler deploy
npx wrangler containers list
```

## 14. Data Refresh Commands

Refresh Scryfall cards:

```bash
python3 -m mtg_agent init --force-download
```

Refresh official precons and tournament aggregates:

```bash
python3 -m mtg_agent corpus sync --source all
```

Refresh only the licensed community dataset:

```bash
python3 -m mtg_agent corpus sync --source kaggle-edhrec
```

Rebuild learned card links:

```bash
python3 -m mtg_agent knowledge sync
```

Check status:

```bash
python3 -m mtg_agent corpus status
python3 -m mtg_agent knowledge status
```

## 15. Legal and Provenance Constraints

- Do not bulk scrape EDHREC, Moxfield, or Archidekt without permission.
- EDHREC pages expose useful bracket aggregates, but its current terms prohibit
  automated repeated queries.
- Moxfield and Archidekt do not provide a supported public bulk-deck API.
- Prefer official APIs, licensed datasets, and owner-authorized exports.
- Preserve source names and whether bracket labels are declared or inferred.

## 16. Known Limitations

- B2-B4 community coverage is currently concentrated in the top 100 commanders.
- Many less-popular commanders still fall back to card mechanics and global
  learned relationships.
- The HTTP server is standard-library based and has no authentication,
  rate-limiting, queueing, or production middleware.
- Cloudflare Quick Tunnel has no uptime guarantee.
- The permanent Cloudflare Container needs Workers Paid activation.
- The container includes a database snapshot; corpus refreshes require rebuilding
  and redeploying the image.
- Prices are Scryfall snapshot values and can become stale.
- The interaction graph stores two blended bands (`core_score` and
  `competitive_score`) rather than four fully independent graph columns.
- Exact imported decks are few.
- There is no Git repository/history in the current workspace.

## 17. Recommended Next Work

Priority order:

1. Ask the user to approve Workers Paid activation, then run `npx wrangler deploy`.
2. Add abuse protection and request limits before advertising the public URL.
3. Expand licensed/authorized Bracket 2-4 coverage beyond the top 100 commanders.
4. Store four independent graph scores instead of two blended bands.
5. Add explicit confidence intervals and coverage warnings per commander.
6. Add background corpus refresh and immutable database version metadata.
7. Move the web UI out of the Python string into maintainable frontend assets.
8. Initialize Git and commit the current working baseline.
9. Add integration tests for all HTTP endpoints and Cloudflare deployment.
10. Consider D1/R2 only as a deliberate architectural migration, not a quick port.

## 18. Cloudflare References

- Containers overview:
  https://developers.cloudflare.com/containers/
- Containers getting started:
  https://developers.cloudflare.com/containers/get-started/
- Container limits:
  https://developers.cloudflare.com/containers/platform-details/limits/
- Upgrade Workers plan:
  https://dash.cloudflare.com/?to=/:account/workers/plans
