# Decksmith: AI Continuation Handoff

Last updated: June 15, 2026

## 1. Project Goal

Build Decksmith, 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.
- Builds suggested complete deck lists through background jobs with polling, so
  long builds are less likely to fail through temporary tunnel interruptions.

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://decksmith-ei9.pages.dev`

Previous overview project:

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

Current complete application through Cloudflare Quick Tunnel:

`https://sao-david-pittsburgh-civilization.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/events.py`: directional cast-plan matching for color-specific,
  multicolor, instant/sorcery, noncreature, type-specific spell triggers, and
  graveyard resource plans.
- `mtg_agent/antifit.py`: negative evidence for cards locked to unrelated
  typal packages or mismatched token resources.
- `mtg_agent/knowledge.py`: learned card-pair interaction graph.
- `mtg_agent/plan_context.py`: semantic plan tags that gate whether learned
  graph evidence is relevant to the commander's actual game plan.
- `mtg_agent/archetype.py`: commander archetype signatures and archetype-transfer
  evidence for thin-coverage commanders.
- `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`
- `commander_archetype`

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

## 7. Current Corpus

Current database totals on June 15, 2026:

- Exact imported decks: 28,081
- Learned card links: 16,271,937
- Commander archetypes: 2,582
- Distinct commanders in card statistics: 2,944
- Oracle cards: 37,686
- SQLite size: 3,365,945,344 bytes

Important nuance: the active `1150-2550` Archidekt crawl has imported more
exact decks into `imported_decks`, but the card-link graph still reflects the
last completed rebuild. Rebuild knowledge after the crawl finishes so the
newly imported decks fully update `card_synergy_edges` and
`commander_archetype`.

Current exact-deck source counts:

- `archidekt_cedh`: 132
- `archidekt_core`: 1,141
- `archidekt_inferred_cedh`: 1,002
- `archidekt_inferred_core`: 1,300
- `archidekt_inferred_optimized`: 12,298
- `archidekt_inferred_upgraded`: 5,912
- `archidekt_optimized`: 569
- `archidekt_unrated`: 3,582
- `archidekt_upgraded`: 1,166
- `edhtop16_topdeck`: 4
- `local_authorized`: 2

The active community crawl focuses on Archidekt Commander decks to improve
Bracket 2, 3, and 4 representation. Some brackets are inferred rather than
owner-declared.

Active crawl status:

- Script: `run_pipeline_1150_2550.py`
- Range: commanders 1150-2550
- Batch size: 50 commanders
- Per-commander fanout: 25 public decks
- Latest completed batch: 4/28
- New decks imported by that process so far: 4,072
- Next final steps inside the script: infer unrated brackets, then rebuild the
  interaction graph and archetype profiles.

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`.

## 8A. Current Quality Safeguards

The recommender now combines positive plan evidence with explicit negative
evidence:

- Shared creature type alone is not enough for synergy.
- Cards locked to an unrelated typal package, such as a Wurm engine in a
  non-Wurm commander plan, receive a strong anti-fit penalty.
- Cards that consume or reward a different named token resource than the
  commander produces are penalized.
- Broad token payoffs are weak evidence for commanders whose tokens are a
  specific typal resource (for example Sliver Queen producing Sliver tokens).
- Learned card-pair graph evidence is context-gated. A card only gets a graph
  boost when its semantic tags match the commander's real plan: exact token
  resource, typal package, cast-event shape, graveyard resource, or meaningful
  archetype. This prevents raw co-occurrence from rescuing cards that only
  share generic words such as "token", "graveyard", or "creature".
- Commander needs are context-aware too: incidental token modes are not treated
  as full token decks, typal token sources become typal plans, multicolor cast
  engines ask for multicolor spells, and Aura/Equipment graveyard commanders
  are not described as generic reanimator decks.
- Combo evidence is package-aware: commander plus one-card combos can justify
  that one card, but multi-piece combos no longer let one isolated piece enter
  by itself unless that piece also has commander-plan/corpus/transfer fit.
  Irrelevant combo signals are also hidden from per-card explanations.
- SQLite connections use a 60-second busy timeout so builds/tests can wait
  through short crawler writes instead of failing with `database is locked`.
- Broad token doublers/payoffs are weak evidence for commanders whose token
  creation is only an incidental color-spell mode (for example Aragorn, the
  Uniter).
- Token logic is generalized through `CommanderTokenPlan`: token text is
  classified as central, typal-secondary, or incidental to another primary
  plan. Real token-engine commanders still keep token doublers/payoffs live.
- Multicolor spells receive direct commander-plan evidence for commanders with
  multiple color-specific cast triggers.
- Cast-trigger commanders use directional event matching: a candidate must
  actually be or amplify the relevant spell/event type rather than merely share
  words with the commander.
- Graveyard commanders use exact resource matching. Aura/Equipment recursion,
  creature recursion, land recursion, and broad graveyard-count plans are not
  treated as interchangeable.
- Anti-fit can be overridden only by strong commander-specific corpus evidence,
  strong mechanical fit, or highly relevant combo evidence.
- Unrelated owned cards are not used as filler to reach 100 cards.

Relevant tests:

- `tests/test_antifit.py`
- `tests/test_plan_context.py`
- `tests/test_recommender.py`
- `tests/test_semantics.py`

Latest local verification on June 15, 2026:

```text
105 passed
```

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.

Archetype-transfer evidence added June 14, 2026:

- About 45% of legal commanders have no deck corpus and many more have only a
  single precon, so their decks previously fell back to one precon or to
  hand-coded mechanics. `mtg_agent/archetype.py` derives candidate evidence for
  these thin commanders by borrowing card-inclusion evidence from
  archetype-similar, well-covered commanders.
- A commander's archetype signature combines the existing mechanic detector with
  a small curated set of oracle-text themes (steal/control, copy, blink, mill,
  lifegain, treasure, pillowfort, etc.) so even unusual commanders sign.
- `commander_archetype` stores each corpus commander's signature, colour
  identity, and deck count. It is rebuilt automatically inside
  `rebuild_knowledge` and surfaced in `knowledge sync` output.
- Transfer is activated only when the commander's own coverage is thin
  (max source deck count below 30). Well-covered commanders are untouched.
- Transfer is recall only. Every borrowed card is re-validated against the
  actual commander: it qualifies as `similar-archetype` plan evidence only if it
  has a directional mechanical fit or itself exhibits one of the commander's
  archetype tags, and only colour-legal peers contribute. Generic staples are
  rejected by this gate.
- Borrowed evidence is discounted (30 of 100 supporting-fit points versus 45 for
  the commander's own corpus) and is labelled distinctly in explanations, naming
  the shared archetype tags and the source commanders.
- A genuinely unique commander with no archetype peers (for example
  Shirei, Shizo's Caretaker) receives no transfer, by design.
- A steal/control commander synergy detector was added to
  `mtg_agent/synergy.py` (sacrifice outlets that consume seized creatures, haste
  granters), with a matching `steal/control` mechanic label.

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.
- Homepage hero/dashboard with visual knowledge metric cards and a more
  thematic CSS background.
- Generated decks include a sticky left-side section navigator for Commander,
  Creature, Instant, Sorcery, Artifact, Enchantment, Planeswalker, Battle,
  Land, and Other blocks.
- Generated decks include an inline full 100-card text-list preview as well as
  deck/shopping/guide downloads.
- 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
105 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 is `Decksmith`.
- 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
