Shared types
The prompt protocol is built from a small set of reusable structures. Instead of redefining them on every prompt page, they’re collected here - each prompt’s arguments link back to the entries it uses.
PromptPresentation
Section titled “PromptPresentation”The title/description header most modal prompts open with. The client is supposed to use this information to add visual clarity about what card or effect triggered the specific prompt being shown.
interface PromptPresentation { title: string; description?: string; text?: string; targets: Array<TargetRef>;}#[serde(rename_all = "camelCase")]pub struct PromptPresentation { pub title: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub description: Option<String>, #[serde(default, skip_serializing_if = "Option::is_none")] pub text: Option<String>, #[serde(default)] pub targets: Vec<TargetRef>,}
References: TargetRef
TargetRef
Section titled “TargetRef”A typed reference to a player, card, or spell. intent and oracle are hints for the UI to optionally annotate the target.
interface TargetRef { kind: TargetKind; id: string; intent?: TargetingIntent; oracle?: string;}#[serde(rename_all = "camelCase")]pub struct TargetRef { pub kind: TargetKind, pub id: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub intent: Option<TargetingIntent>, #[serde(default, skip_serializing_if = "Option::is_none")] pub oracle: Option<String>,}
References: TargetKind , TargetingIntent
TargetKind
Section titled “TargetKind”Which id space a TargetRef points into - a player, a card, or a
spell on the stack.
type TargetKind = "player" | "card" | "spell";#[serde(rename_all = "camelCase")]pub enum TargetKind { Player, Card, Spell,}ScryDestination
Section titled “ScryDestination”Specifically used for scry-style prompts that need to sort and divide cards into specific zones.
type ScryDestination = | "libraryTop" | "libraryBottom" | "graveyard" | "exile" | "hand";#[serde(rename_all = "camelCase")]pub enum ScryDestination { LibraryTop, LibraryBottom, Graveyard, Exile, Hand,}DiceRollEntry
Section titled “DiceRollEntry”One player’s dice result.
interface DiceRollEntry { label?: string; playerId?: string; round: number; naturalResults: Array<number>; finalResults: Array<number>; ignoredRolls: Array<number>; highlighted: boolean;}#[serde(rename_all = "camelCase")]pub struct DiceRollEntry { #[serde(default, skip_serializing_if = "Option::is_none")] pub label: Option<String>, #[serde(default, skip_serializing_if = "Option::is_none")] pub player_id: Option<String>, #[serde(default)] pub round: u32, pub natural_results: Vec<i32>, pub final_results: Vec<i32>, pub ignored_rolls: Vec<i32>, #[serde(default)] pub highlighted: bool,}AvailableAction
Section titled “AvailableAction”One legal action. Offered by chooseAction: cast a spell, activate an ability, or undo a mana activation.
type AvailableAction = { id: string } & ( | { type: "cast"; cardId: string; mode: PlayCardMode; label: string } | ({ type: "activateAbility" } & ActivatableAbilityInfo) | { type: "undoMana"; cardId: string });pub struct AvailableAction { pub id: String, #[serde(flatten)] pub kind: AvailableActionKind,}
References: ActivatableAbilityInfo , PlayCardMode
ActivatableAbilityInfo
Section titled “ActivatableAbilityInfo”A mana ability the player can activate while paying a cost (payManaCost).
interface ActivatableAbilityInfo { cardId: string; abilityIndex: number; description: string; isManaAbility: boolean; isClassLevelUp?: boolean; cost?: string; producedMana?: Array<Mana>;}#[serde(rename_all = "camelCase")]pub struct ActivatableAbilityInfo { pub card_id: String, pub ability_index: usize, pub description: String, pub is_mana_ability: bool, #[serde(default, skip_serializing_if = "Option::is_none")] pub is_class_level_up: Option<bool>, #[serde(default, skip_serializing_if = "Option::is_none")] pub cost: Option<String>, #[serde(default, skip_serializing_if = "Option::is_none")] pub produced_mana: Option<Vec<Mana>>,}
References: Mana
AttackerOptionDto
Section titled “AttackerOptionDto”A creature that can attack, with the set of targets it may attack (chooseAttackers).
interface AttackerOptionDto { attackerId: string; validTargetIds: Array<string>; mustAttack: boolean;}#[serde(rename_all = "camelCase")]pub struct AttackerOptionDto { pub attacker_id: String, pub valid_target_ids: Vec<String>, pub must_attack: bool,}AttackTargetDto
Section titled “AttackTargetDto”Something an attacker can be declared against - a player, planeswalker, or battle.
interface AttackTargetDto { id: string; label: string; kind: AttackTargetKind;}#[serde(rename_all = "camelCase")]pub struct AttackTargetDto { pub id: String, pub label: String, pub kind: AttackTargetKind,}
References: AttackTargetKind
AttackTargetKind
Section titled “AttackTargetKind”Which kind of thing an AttackTargetDto is.
type AttackTargetKind = "player" | "planeswalker" | "battle";#[serde(rename_all = "camelCase")]pub enum AttackTargetKind { Player, Planeswalker, Battle,}BlockableAttackerDto
Section titled “BlockableAttackerDto”An incoming attacker and how it may be blocked (chooseBlockers).
interface BlockableAttackerDto { attackerId: string; validBlockerIds: Array<string>; minBlockers: number; maxBlockers?: number; mustBeBlocked: boolean;}#[serde(rename_all = "camelCase")]pub struct BlockableAttackerDto { pub attacker_id: String, pub valid_blocker_ids: Vec<String>, pub min_blockers: u32, #[serde(default, skip_serializing_if = "Option::is_none")] pub max_blockers: Option<u32>, pub must_be_blocked: bool,}TokenScript
Section titled “TokenScript”Taken directly from the Forge spec. This is a definition used to distinguish tokens with the same name but different rules, such as two 2/2 white Knight tokens with different abilities. It is an opaque string on the wire.
Examples are w_2_2_knight_vigilance or w_2_2_knight_flying
See Forge’s
tokenscripts
directory for the canonical definitions.
type TokenScript = string;#[serde(transparent)]pub struct TokenScript(pub String);