MTG Copilot Docs
AI

Recommendations

How a recommendation is produced: hard filters, semantic ranking, and a model choosing sixteen with reasons.

Recommendations answer "what should I add to this deck". The work splits between a database query that decides what is eligible and a model call that decides what is good.

The path

Hard filters run your query through the same executor the search page uses, with no limit. Cards already in the deck are removed. This step decides eligibility, so a card that fails a filter cannot be recommended no matter how relevant it seems.

Semantic ranking embeds your stated intent and takes the 200 nearest cards across the whole database, then keeps only those that passed the filters, preserving the semantic order. Eligible cards that were not in the top 200 are appended after the ranked ones, so nothing is dropped but the tail is unordered.

What each card is compared against matters here. A card's embedding is built from its oracle text and type line plus its keywords and its semantic tags, so a card tagged ramp carries that word in what was embedded even when its rules text never says it. Searching for ramp finds tagged ramp. The catch is that embeddings are generated in batches rather than on write, so a tag added since the last run is not yet reflected in the vector, and a recently tagged card can rank lower than its tag suggests.

Selection. The top 40 go to Sonnet along with the deck's commander, color identity, play style, themes, win conditions, overview and full list. It returns 16 cards with a sentence each on why the card fits this deck.

Name matching. Each returned name is matched back to the candidates it was shown. A name that does not match is discarded, so an invented card cannot reach you. It also means you can receive fewer than 16 suggestions, and nothing says so.

What this shapes

The model chooses from 40 cards. Whatever hard filters and embedding similarity put in the top 40 is the entire universe for that request. A card that would have been better and ranked 41st was never seen. Widening a query changes the candidate pool more than rewording the intent does.

Ranking is intent-driven, not deck-driven. The embedding compares against what you typed, so vague intent ranks vaguely. "Ramp" and "ways to accelerate into my seven drop commander a turn early" produce different orderings.

Reasons can be canned. If the model call fails, the top candidates by similarity are returned with a generic sentence about semantic relevance rather than a deck-specific one. A reason that does not mention anything about your deck is that fallback.

Ranking degrades quietly. If the embedding call fails, results fall back to filter order, which is not a relevance ordering at all. Cards without embeddings sit at the end of any ranked list.

More matches

The full ranked list is kept, and paging through "more matches" walks it in order without further model involvement. Those cards passed the same filters and carry the same ranking, they just have no written reason attached.

What to check

The 16 picks are a judgement over a candidate pool, and both halves can be wrong. The pool is reproducible: run the same query on the search page and you see what was eligible. The judgement is not, and a reason that names your commander and an existing card is doing more work than one that describes the card in isolation.

On this page