MTG Copilot Docs
AI

The chat pipeline

The five layers a chat message passes through, what each one loads, and what the reasoner can fetch for itself.

Chat is the most grounded surface in the app. A message passes through five layers before the model writes anything, and the model can fetch more as it reasons.

The layers exist to put the right context in the prompt before the expensive model runs, so the reasoner spends its tool calls on what pre-loading missed rather than on everything.

The five layers

Only the last layer writes anything. The first four decide what the model gets to see, which is where most of the difference between a good answer and a vague one is settled.

Not every turn runs all of them. A greeting is caught by a pattern before classification and skips the two layers after it. A question the classifier reads as unrelated to your deck skips the deck load, so the model answers without your list even though it is sitting in the database.

A layer that fails does not stop the turn either. Each one catches its own errors and carries on with less context, so a degraded answer is more likely than an error message. That is the right tradeoff for a chat box and it does mean quality varies for reasons the answer itself will not mention.

Prechecks

Credit balance, then a rate limit of 10 messages per minute counted across your conversations.

Classification

A short Haiku call reads the conversation and returns an intent (recommendations, analysis, rules or chat), a confidence, and flags for what to pre-load. Greetings skip it entirely on a regex, which also skips the two layers after it.

Rules are the interesting case. The rules flag is hardcoded to false, so nothing rules-related is ever pre-loaded. Rules reach the model two other ways: a compressed rules summary sits in every prompt, and the reasoner has three tools for fetching specifics. The reasoning is that a query derived at classify time picks worse passages than the model's own mid-reasoning lookups. That tradeoff is worth knowing about, because it means rules accuracy depends entirely on tool calls the model chooses to make.

Concept resolution

Working out which game concepts a message is about runs three paths at once:

  1. Fuzzy string matching against the 833 concept names.
  2. Vector similarity between the message embedding and stored concept embeddings.
  3. A Haiku call.

The results merge with agreement scoring, so a concept found by two paths outranks one proposed by a single path. The model path is the one that invents plausible category names that do not exist. The other two can only return vocabulary that does, so agreement between paths carries information. See taxonomy and tagging for the vocabulary itself.

Context loading

Driven by the flags from classification:

FlagWhat loads
deck_designName, commander, counts, overview, themes, power level, play style, win conditions, notes
deck_cardsFull oracle text for every card in the deck
analysisA summary of stored analysis results for the deck
knowledgeNothing today. See below

Concept definitions load whenever concept resolution returned anything, pulling in definitions for tags on the deck's own cards as well.

Card searching is deliberately absent here. Finding candidate cards is left to the reasoner, which can see what it already has and search for what it lacks.

The knowledge flag is the one to know about. It is wired end to end and has nothing to read: it is meant to fetch deck-building theory by similarity to your message, and the classifier still sets it, but the corpus behind it is not built yet, so the fetch returns nothing and the block is omitted. Strategic advice today comes from the model rather than from curated theory. That work is in progress, and the knowledge layer describes where it is going.

Prompt assembly

Blocks are ordered so the stable ones can be cached, which makes repeat turns about ten times cheaper on those tokens:

  1. Static instructions.
  2. Compressed rules.
  3. Intent framing.
  4. Deck identity.
  5. Full deck oracle text.

Then the per-turn blocks: resolved tags, concept definitions, deck notes, knowledge passages, analysis summary, and a line about where in the app you are.

The deck oracle block is not truncated. A 100 card deck contributes its complete text every turn. This is a deliberate cost: rules text is precise, and the tokens are cheap on a cache hit.

Reasoning

Sonnet runs a tool loop, up to five rounds. Available tools:

ToolReturns
get_cardOne card by name, with full text and a count of its rulings
search_cardsUp to 20 cards for a query, re-ranked by similarity to the query
load_conceptsDefinitions for concept slugs
load_rulesFive matching Comprehensive Rules entries plus their section siblings
load_card_rulingsOfficial rulings for named cards
load_rules_examplesCurated worked examples of interactions

web_search is added only when you turn it on and the classifier thought it would help.

search_cards applies your deck's color identity and commander legality by default, so it will not offer you cards you cannot play. Including ci<= or f: in the query overrides that.

Its results are ordered by semantic similarity to the query rather than by the database's own order, using the same card embeddings the recommendations surface ranks with. Those embeddings cover oracle text, type line, keywords and semantic tags, so a query for a concept can surface a card tagged with it even when the card never says the word.

If five rounds pass without an answer, the tools are removed and the model is asked to respond with what it found. Those answers carry the least verification of any the system produces, and hard rules questions are where they happen. See grounding and limits.

After the answer

The turn is persisted, token usage logged, timings recorded, and card names in the reply resolved against the database so they render as hover cards.

What this means when an answer is wrong

The pipeline explains most failures.

It ignored something in my deck. The deck was in context if the classifier set deck_cards. If it decided your question was not about deck contents, the oracle block was never assembled. Asking a more explicitly deck-shaped question changes the classification.

It gave up on a rules question. Probably the five round budget. Ask about one interaction at a time.

It missed an obvious card. search_cards returns 20 per call. Narrowing the query does more than repeating the request.

On this page