MTG Copilot Docs
Your data

AI conversations

What a chat turn writes to the database, the diagnostic trace kept alongside it, and how AI spend is recorded against your credit balance.

One chat turn writes to four tables. Your message and the reply go to ai_messages under a thread in ai_conversations. A diagnostic record of how the turn was answered goes to ai_turn_logs and ai_pipeline_events. The cost goes to token_usage, which is also what moves your credit balance.

All five are yours: the policies check auth.uid() against the row's user_id, or reach it through the conversation or turn log the row belongs to. The sixth table on this page, ai_audit_findings, is a maintainer tool and is covered at the end.

Threads and messages

ai_conversations is one row per thread.

ColumnWhat it holds
deck_idThe deck the thread is attached to, when there is one.
context_typedeck_sidebar, search, general or recommendations.
parametersInputs for the run. A recommendation thread stores the intent and query here.
is_favoriteWhether you starred the thread.
created_at, updated_atupdated_at is touched on every turn, which is what orders the thread list.

context_snapshot, ended_at, satisfaction and cards_added_count exist on the table and nothing writes them today.

ai_messages gets two rows per turn, one for what you sent and one for the reply.

ColumnWhat it holds
roleuser or assistant.
contentThe message text, stored verbatim.
cards_mentionedCard names pulled out of the reply's [[Card]] notation.
tools_calledWhich tools the model used on that turn.
topics_detectedTopic labels from the classifier.
input_tokens, output_tokens, cache_read_tokens, cache_creation_tokensToken counts for the reply.

search_query and implicit_signal are unwritten columns.

A recommendation run stores itself the same way, as a thread with one user message holding your intent and one assistant message listing each suggested card with its reason.

The pipeline trace

Two tables record how a turn was answered rather than what it said. Both are diagnostic, both are readable only by you, and neither is read by the chat UI.

ai_turn_logs gets one row per turn: classifier_output and domain_resolution for how the question was classified, context_slots_loaded for which pieces of deck context were pulled in, tool_calls_made, unresolved_themes, and token_usage and latency_ms as per-stage JSON breakdowns.

ai_pipeline_events is the step-by-step trace under that. Events accumulate in memory during the turn and are written in one insert after it finishes, ordered by seq, so the trace costs the request nothing. kind is one of classifier, context_load, domain_resolution, prompt_assembly, reasoning, sonnet_call, tool_call, turn_complete and error, and data holds that step's payload.

The payload is a record of the pipeline's own work, and it quotes what went through it. A prompt_assembly or tool_call event can therefore contain parts of your message and of your deck.

Spend

token_usage gets one row per billable AI action, whether or not it came from a chat: deck analysis and recommendations write here too.

ColumnWhat it holds
action_typechat, recommendation, deck_analysis or semantic_search.
modelThe model that ran.
tokens_input, tokens_output, tokens_cachedToken counts. A cached input token costs a tenth of a fresh one.
cost_usdWhat the call cost us at list rates.
cost_with_markupWhat was taken off your balance: cost_usd plus a 10% infrastructure markup.
refunded_atSet when a charge is refunded.
deck_id, conversation_id, message_idWhat the spend was attached to, where it applies.

Every insert is followed by deduct_credits, which is the only path that lowers credits_usd. Credit purchases land in the same table with an action_type of credit_purchase, a negative cost_with_markup, and the Stripe payment intent id in model, so a webhook delivered twice cannot credit you twice. Your billing page reads the 50 most recent rows.

Retention

Nothing expires, and the app has no self-serve path for deleting a conversation today. Threads, messages, turn logs and pipeline events keep accumulating on the account. Ask us if you want a thread removed.

ai_audit_findings

This one holds no user content. A script run out of band samples recent pipeline events, has a model critique each turn against a rubric, and writes what it finds: a severity of low, medium or high, a category from a fixed list such as classifier_misprediction or confident_wrong, a summary, and an optional suggestion. Rows point at a turn log and carry no user_id.

Reads are restricted by policy to the maintainer list, and the script writes with the service role key. It exists so failures in the pipeline get found and fixed.

On this page