{
  "$schema": "https://bangarena.app/rules/ai.json#v1",
  "game": "BangArena",
  "packId": "PACK_DEFAULT_V0",
  "rulesetVersion": "krug_rules@0.1.0",
  "protocolVersion": "krug-decision/1",
  "decisionDeadlineMs": 30000,
  "offlineDecisionMs": 8000,
  "aiSeatTimeoutMsDefault": 15000,
  "drawPerTurn": 2,
  "shotsPerTurn": 1,
  "illegalPolicyDefault": "reask_then_random",
  "seats": {
    "min": 4,
    "max": 8
  },
  "roleModes": [
    "classic",
    "partners",
    "impostor"
  ],
  "roles": [
    {
      "id": "marshal",
      "name": {
        "ru": "Маршал",
        "en": "Marshal"
      },
      "team": "law",
      "public": true,
      "extraMaxHp": 1,
      "jailImmune": true,
      "winPredicateId": "law_clears_table",
      "killRewardDraw": 0,
      "penaltyForKillingAide": true
    },
    {
      "id": "aide",
      "name": {
        "ru": "Помощник",
        "en": "Deputy"
      },
      "team": "law",
      "public": false,
      "extraMaxHp": 0,
      "jailImmune": false,
      "winPredicateId": "law_clears_table",
      "killRewardDraw": 0,
      "penaltyForKillingAide": false
    },
    {
      "id": "raider",
      "name": {
        "ru": "Налётчик",
        "en": "Raider"
      },
      "team": "raiders",
      "public": false,
      "extraMaxHp": 0,
      "jailImmune": false,
      "winPredicateId": "marshal_dead_and_not_lone_only",
      "killRewardDraw": 2,
      "penaltyForKillingAide": false
    },
    {
      "id": "lone",
      "name": {
        "ru": "Одиночка",
        "en": "Loner"
      },
      "team": "lone",
      "public": false,
      "extraMaxHp": 0,
      "jailImmune": false,
      "winPredicateId": "sole_survivor",
      "killRewardDraw": 0,
      "penaltyForKillingAide": false
    },
    {
      "id": "impostor",
      "name": {
        "ru": "Двойной агент",
        "en": "Double Agent"
      },
      "team": "raiders",
      "public": false,
      "extraMaxHp": 0,
      "jailImmune": false,
      "winPredicateId": "marshal_dead_and_not_lone_only",
      "killRewardDraw": 0,
      "penaltyForKillingAide": false
    }
  ],
  "winPredicates": {
    "law_clears_table": "All living players have team != raiders and team != lone (the impostor is team raiders). Dead aides still win with marshal.",
    "marshal_dead_and_not_lone_only": "Marshal is dead AND living count != 1 with that living player team == lone. All raiders win including dead raiders.",
    "sole_survivor": "Exactly one living player and that player team == lone.",
    "marshal_killed_by_raider_while_impostor_alive": "LEGACY (sim only, W4R_DEFAULTS.impostorWin='raider_kill'): Marshal killed by a raider while the impostor lives → impostor wins alone. Live rule since IMP-2 (11.10.2026): the impostor is team raiders and wins with them.",
    "lones_only_left": "Role mode partners only. Every living player is a lone → all lones win (dead lones too)."
  },
  "roleTable": {
    "classic": [
      {
        "seats": 4,
        "roles": {
          "marshal": 1,
          "aide": 0,
          "raider": 2,
          "lone": 1,
          "impostor": 0
        }
      },
      {
        "seats": 5,
        "roles": {
          "marshal": 1,
          "aide": 1,
          "raider": 2,
          "lone": 1,
          "impostor": 0
        }
      },
      {
        "seats": 6,
        "roles": {
          "marshal": 1,
          "aide": 1,
          "raider": 3,
          "lone": 1,
          "impostor": 0
        }
      },
      {
        "seats": 7,
        "roles": {
          "marshal": 1,
          "aide": 2,
          "raider": 3,
          "lone": 1,
          "impostor": 0
        }
      },
      {
        "seats": 8,
        "roles": {
          "marshal": 1,
          "aide": 2,
          "raider": 3,
          "lone": 2,
          "impostor": 0
        }
      }
    ],
    "impostor": [
      {
        "seats": 5,
        "roles": {
          "marshal": 1,
          "aide": 1,
          "raider": 1,
          "lone": 1,
          "impostor": 1
        }
      },
      {
        "seats": 6,
        "roles": {
          "marshal": 1,
          "aide": 1,
          "raider": 2,
          "lone": 1,
          "impostor": 1
        }
      },
      {
        "seats": 7,
        "roles": {
          "marshal": 1,
          "aide": 2,
          "raider": 2,
          "lone": 1,
          "impostor": 1
        }
      },
      {
        "seats": 8,
        "roles": {
          "marshal": 1,
          "aide": 2,
          "raider": 2,
          "lone": 2,
          "impostor": 1
        }
      }
    ]
  },
  "defaultWeapon": {
    "id": "weapon_revolver",
    "name": {
      "ru": "Револьвер",
      "en": "Revolver"
    },
    "range": 1
  },
  "cards": [
    {
      "id": "shot",
      "name": {
        "ru": "Выстрел",
        "en": "Shot"
      },
      "kind": "brown",
      "copies": 25,
      "range": null,
      "unlimitedShot": false,
      "command": "play_shot",
      "effect": {
        "ru": "Нанеси 1 урон игроку в дальности оружия (1 раз за ход). Спасают Укрытие и Рикошет.",
        "en": "Deal 1 damage to a player in weapon range (once per turn). Cover and Ricochet stop it."
      }
    },
    {
      "id": "miss",
      "name": {
        "ru": "Рикошет",
        "en": "Ricochet"
      },
      "kind": "brown",
      "copies": 12,
      "range": null,
      "unlimitedShot": false,
      "command": "play_miss",
      "effect": {
        "ru": "Реакция: отмени направленный в тебя Выстрел или удар Картечи.",
        "en": "Reaction: cancel a Shot or a Buckshot hit aimed at you."
      }
    },
    {
      "id": "heal_self",
      "name": {
        "ru": "Фляга",
        "en": "Flask"
      },
      "kind": "brown",
      "copies": 6,
      "range": null,
      "unlimitedShot": false,
      "command": "play_heal_self",
      "effect": {
        "ru": "+1 ♥ себе. В чужой ход — только при 1 ♥ против Выстрела или Картечи и если живых >2.",
        "en": "Heal 1 ♥. Off-turn only at 1 ♥ vs a Shot or Buckshot, and only with 3+ alive."
      }
    },
    {
      "id": "steal_near",
      "name": {
        "ru": "Выхватить",
        "en": "Snatch"
      },
      "kind": "brown",
      "copies": 4,
      "range": null,
      "unlimitedShot": false,
      "command": "play_steal",
      "effect": {
        "ru": "Забери у игрока на дистанции 1 карту со стола на выбор или случайную с руки.",
        "en": "Take a card from a player at distance 1: your pick from play or a random one from hand."
      }
    },
    {
      "id": "discard_any",
      "name": {
        "ru": "Сбросить",
        "en": "Toss"
      },
      "kind": "brown",
      "copies": 4,
      "range": null,
      "unlimitedShot": false,
      "command": "play_discard_any",
      "effect": {
        "ru": "Сбрось у любого игрока карту со стола на выбор или случайную с руки.",
        "en": "Discard a card from any player: your pick from play or a random one from hand."
      }
    },
    {
      "id": "duel",
      "name": {
        "ru": "Поединок",
        "en": "Duel"
      },
      "kind": "brown",
      "copies": 3,
      "range": null,
      "unlimitedShot": false,
      "command": "play_duel",
      "effect": {
        "ru": "Вызови любого игрока: по очереди сбрасываете Выстрел, первым — он; кто не смог — −1 ♥.",
        "en": "Challenge any player: take turns discarding a Shot, they go first; whoever can't loses 1 ♥."
      }
    },
    {
      "id": "raid",
      "name": {
        "ru": "Набег",
        "en": "Raid"
      },
      "kind": "brown",
      "copies": 2,
      "range": null,
      "unlimitedShot": false,
      "command": "play_raid",
      "effect": {
        "ru": "Каждый другой игрок сбрасывает Выстрел или теряет 1 ♥.",
        "en": "Every other player discards a Shot or loses 1 ♥."
      }
    },
    {
      "id": "draw2",
      "name": {
        "ru": "Обоз",
        "en": "Wagon"
      },
      "kind": "brown",
      "copies": 2,
      "range": null,
      "unlimitedShot": false,
      "command": "play_draw",
      "effect": {
        "ru": "Возьми 2 карты из колоды.",
        "en": "Draw 2 cards from the deck."
      }
    },
    {
      "id": "market",
      "name": {
        "ru": "Базар",
        "en": "Bazaar"
      },
      "kind": "brown",
      "copies": 2,
      "range": null,
      "unlimitedShot": false,
      "command": "play_market",
      "effect": {
        "ru": "Каждый живой игрок берёт 1 карту из колоды — по кругу, начиная с тебя.",
        "en": "Every living player draws 1 card from the deck, clockwise starting with you."
      }
    },
    {
      "id": "heal_all",
      "name": {
        "ru": "Салун",
        "en": "Saloon"
      },
      "kind": "brown",
      "copies": 1,
      "range": null,
      "unlimitedShot": false,
      "command": "play_heal_all",
      "effect": {
        "ru": "Каждый живой игрок восстанавливает 1 ♥.",
        "en": "Every living player heals 1 ♥."
      }
    },
    {
      "id": "draw3",
      "name": {
        "ru": "Караван",
        "en": "Caravan"
      },
      "kind": "brown",
      "copies": 1,
      "range": null,
      "unlimitedShot": false,
      "command": "play_draw",
      "effect": {
        "ru": "Возьми 3 карты из колоды.",
        "en": "Draw 3 cards from the deck."
      }
    },
    {
      "id": "aoe_shot",
      "name": {
        "ru": "Картечь",
        "en": "Buckshot"
      },
      "kind": "brown",
      "copies": 1,
      "range": null,
      "unlimitedShot": false,
      "command": "play_aoe_shot",
      "effect": {
        "ru": "Каждый другой получает 1 урон; спасают Укрытие и Рикошет. Лимит Выстрелов не тратит.",
        "en": "Every other player takes 1 damage; Cover and Ricochet stop it. Doesn't use your Shot limit."
      }
    },
    {
      "id": "jail",
      "name": {
        "ru": "Тюрьма",
        "en": "Jail"
      },
      "kind": "blue",
      "copies": 3,
      "range": null,
      "unlimitedShot": false,
      "command": "play_equip_blue",
      "effect": {
        "ru": "Посади игрока (не Маршала). В начале его хода: ♥ — играет, иначе добор без розыгрыша. Тюрьма — в сброс.",
        "en": "Jail a player (not the Marshal). Turn start: ♥ plays, else they draw but can't play. Jail is discarded."
      }
    },
    {
      "id": "cover",
      "name": {
        "ru": "Укрытие",
        "en": "Cover"
      },
      "kind": "blue",
      "copies": 2,
      "range": null,
      "unlimitedShot": false,
      "command": "play_equip_blue",
      "effect": {
        "ru": "В тебя Выстрел или Картечь — бросок 50 на 50: повезло — удар отменён. Нет — можно Рикошет.",
        "en": "Hit by a Shot or Buckshot? A 50/50 flip: lucky — the hit is cancelled. If not, you can still Ricochet."
      }
    },
    {
      "id": "mount",
      "name": {
        "ru": "Конь",
        "en": "Horse"
      },
      "kind": "blue",
      "copies": 2,
      "range": null,
      "unlimitedShot": false,
      "command": "play_equip_blue",
      "effect": {
        "ru": "Другие видят тебя на 1 дальше.",
        "en": "Others see you at +1 distance."
      }
    },
    {
      "id": "scope",
      "name": {
        "ru": "Прицел",
        "en": "Scope"
      },
      "kind": "blue",
      "copies": 1,
      "range": null,
      "unlimitedShot": false,
      "command": "play_equip_blue",
      "effect": {
        "ru": "Ты видишь других на 1 ближе, но не ближе 1.",
        "en": "You see others at −1 distance (minimum 1)."
      }
    },
    {
      "id": "bomb",
      "name": {
        "ru": "Динамит",
        "en": "Dynamite"
      },
      "kind": "blue",
      "copies": 1,
      "range": null,
      "unlimitedShot": false,
      "command": "play_equip_blue",
      "effect": {
        "ru": "Перед собой. В начале хода, до Тюрьмы: пики 2–9 — 3 урона, иначе — следующему по ходу.",
        "en": "Place it before you. Start of turn, before Jail: spades 2–9 deal 3 damage, else it passes to the next player."
      }
    },
    {
      "id": "weapon_volcanic",
      "name": {
        "ru": "Вулкан",
        "en": "Volcanic"
      },
      "kind": "weapon",
      "copies": 2,
      "range": 1,
      "unlimitedShot": true,
      "command": "play_weapon",
      "effect": {
        "ru": "Оружие: дальность 1, Выстрелы без лимита.",
        "en": "Weapon: range 1, unlimited Shots."
      }
    },
    {
      "id": "weapon_short",
      "name": {
        "ru": "Обрез",
        "en": "Sawed-Off"
      },
      "kind": "weapon",
      "copies": 3,
      "range": 2,
      "unlimitedShot": false,
      "command": "play_weapon",
      "effect": {
        "ru": "Оружие: дальность 2.",
        "en": "Weapon: range 2."
      }
    },
    {
      "id": "weapon_rifle",
      "name": {
        "ru": "Ружьё",
        "en": "Rifle"
      },
      "kind": "weapon",
      "copies": 1,
      "range": 3,
      "unlimitedShot": false,
      "command": "play_weapon",
      "effect": {
        "ru": "Оружие: дальность 3.",
        "en": "Weapon: range 3."
      }
    },
    {
      "id": "weapon_carbine",
      "name": {
        "ru": "Карабин",
        "en": "Carbine"
      },
      "kind": "weapon",
      "copies": 1,
      "range": 4,
      "unlimitedShot": false,
      "command": "play_weapon",
      "effect": {
        "ru": "Оружие: дальность 4.",
        "en": "Weapon: range 4."
      }
    },
    {
      "id": "weapon_long",
      "name": {
        "ru": "Винтовка",
        "en": "Long Rifle"
      },
      "kind": "weapon",
      "copies": 1,
      "range": 5,
      "unlimitedShot": false,
      "command": "play_weapon",
      "effect": {
        "ru": "Оружие: дальность 5.",
        "en": "Weapon: range 5."
      }
    }
  ],
  "characters": [
    {
      "id": "char_01",
      "name": {
        "ru": "Каменный Барс",
        "en": "Stone Leopard"
      },
      "maxHp": 3,
      "ability": {
        "ru": "За каждый удар (даже от Динамита) берёт 1 карту из колоды, а если осталось 2 ♥ или меньше — 2 карты.",
        "en": "Draws 1 card from the deck for every hit taken (even Dynamite) — 2 cards if the hit leaves them at 2 ♥ or less."
      },
      "protocol": null
    },
    {
      "id": "char_02",
      "name": {
        "ru": "Красная Масть",
        "en": "Red Suit"
      },
      "maxHp": 4,
      "ability": {
        "ru": "В доборе открывает вторую карту: если красная — берёт ещё 1.",
        "en": "In the draw, reveals the 2nd card: if it's red, draws 1 more."
      },
      "protocol": null
    },
    {
      "id": "char_03",
      "name": {
        "ru": "Двуликая",
        "en": "Two-Faced"
      },
      "maxHp": 4,
      "ability": {
        "ru": "Выстрел можно сыграть как Рикошет, а Рикошет — как Выстрел.",
        "en": "Can play a Shot as a Ricochet and a Ricochet as a Shot."
      },
      "protocol": "legal items with args.playedAs (\"shot\" / \"miss\") — a Ricochet listed as a Shot and back"
    },
    {
      "id": "char_04",
      "name": {
        "ru": "Данник",
        "en": "Tollman"
      },
      "maxHp": 3,
      "ability": {
        "ru": "Получив урон от игрока, тянет у него случайную карту из руки.",
        "en": "When hit by a player, takes a random card from their hand."
      },
      "protocol": null
    },
    {
      "id": "char_05",
      "name": {
        "ru": "Хват",
        "en": "Grip"
      },
      "maxHp": 4,
      "ability": {
        "ru": "Первую карту добора может вытянуть из чужой руки наугад.",
        "en": "May take the first draw at random from another player's hand."
      },
      "protocol": "pending choice → choose_first_draw"
    },
    {
      "id": "char_06",
      "name": {
        "ru": "Железный Лоб",
        "en": "Iron Brow"
      },
      "maxHp": 4,
      "ability": {
        "ru": "Всегда в Укрытии — даже без карты; карта Укрытия второй проверки не добавляет.",
        "en": "Always has Cover, card or no card; a Cover card adds no second check."
      },
      "protocol": null
    },
    {
      "id": "char_07",
      "name": {
        "ru": "Три Глаза",
        "en": "Three Eyes"
      },
      "maxHp": 4,
      "ability": {
        "ru": "В доборе смотрит 3 верхние карты: 2 берёт, 1 кладёт обратно наверх.",
        "en": "In the draw, looks at the top 3: keeps 2, puts 1 back on top."
      },
      "protocol": "pending choice → choose_look_top"
    },
    {
      "id": "char_08",
      "name": {
        "ru": "Счастливчик",
        "en": "Lucky"
      },
      "maxHp": 4,
      "ability": {
        "ru": "На проверке — две попытки, засчитывается удачная.",
        "en": "On a check — two tries, the better one counts."
      },
      "protocol": null
    },
    {
      "id": "char_09",
      "name": {
        "ru": "Тень Перевала",
        "en": "Pass Shadow"
      },
      "maxHp": 3,
      "ability": {
        "ru": "Всегда верхом: встроенный Конь, до него на 2 дальше.",
        "en": "Always mounted: a built-in Horse, they count as 2 farther away."
      },
      "protocol": null
    },
    {
      "id": "char_10",
      "name": {
        "ru": "Стервятник-младший",
        "en": "Vulture Jr."
      },
      "maxHp": 4,
      "ability": {
        "ru": "Первую карту добора может взять с верха сброса. Когда кто-то выбывает, берёт 2 карты из колоды.",
        "en": "May take the first draw from the top of the discard pile. When someone is eliminated, draws 2 cards from the deck."
      },
      "protocol": "pending choice → choose_first_draw"
    },
    {
      "id": "char_11",
      "name": {
        "ru": "Орлиный Глаз",
        "en": "Eagle Eye"
      },
      "maxHp": 4,
      "ability": {
        "ru": "Бьёт дальше: Прицел встроен.",
        "en": "Shoots farther: built-in Scope."
      },
      "protocol": null
    },
    {
      "id": "char_12",
      "name": {
        "ru": "Костоправ",
        "en": "Bonesetter"
      },
      "maxHp": 5,
      "ability": {
        "ru": "В любой момент: сбрось 2 карты — +1 ♥. Не выше максимума и не с нуля.",
        "en": "Any time: discard 2 cards to heal 1 ♥. Not above max, not from zero."
      },
      "protocol": "use_discard_heal items"
    },
    {
      "id": "char_13",
      "name": {
        "ru": "Двойной Ствол",
        "en": "Double Barrel"
      },
      "maxHp": 4,
      "ability": {
        "ru": "Вплотную от его Выстрела спасают только 2 Рикошета (Укрытие — за один). Дальше хватает одного.",
        "en": "Point-blank (distance 1), dodging their Shot takes 2 Ricochets (Cover counts as one). Farther away, one is enough."
      },
      "protocol": "targets of their Shot need 2 Ricochets"
    },
    {
      "id": "char_14",
      "name": {
        "ru": "Пустые Руки",
        "en": "Empty Hands"
      },
      "maxHp": 4,
      "ability": {
        "ru": "Рука опустела — сразу берёт 1 карту.",
        "en": "Hand empty? Draws 1 card right away."
      },
      "protocol": null
    },
    {
      "id": "char_15",
      "name": {
        "ru": "Падальщик",
        "en": "Scavenger"
      },
      "maxHp": 4,
      "ability": {
        "ru": "Когда кто-то выбывает, забирает его руку и выложенные карты.",
        "en": "When someone is eliminated, takes their hand and cards in play."
      },
      "protocol": null
    },
    {
      "id": "char_16",
      "name": {
        "ru": "Бешеный",
        "en": "Mad Dog"
      },
      "maxHp": 4,
      "ability": {
        "ru": "Стреляет без лимита: сколько угодно Выстрелов за ход. И видит на 1 дальше: Прицел встроен.",
        "en": "No shot limit: play as many Shots per turn as you like. And sees 1 farther: built-in Scope."
      },
      "protocol": "play_shot stays legal after the first Shot"
    }
  ],
  "deck": {
    "size": 80,
    "bySuit": {
      "hearts": 21,
      "diamonds": 20,
      "clubs": 20,
      "spades": 19
    },
    "hearts": 21,
    "spades2to9": 12
  },
  "commands": [
    {
      "command": "play_shot",
      "when": "play (own turn)",
      "args": "{ cardUid, targetSeat, playedAs? }",
      "actionId": "shot:<cardUid>:<targetSeat>",
      "note": "Shot at a seat within range. Once per turn unless unlimited."
    },
    {
      "command": "play_aoe_shot",
      "when": "play",
      "args": "{ cardUid }",
      "actionId": "aoe_shot:<cardUid>",
      "note": "Buckshot: 1 damage to every other player, each may answer. Does not use the Shot limit."
    },
    {
      "command": "play_raid",
      "when": "play",
      "args": "{ cardUid }",
      "actionId": "raid:<cardUid>",
      "note": "Raid: every other player discards a Shot or loses 1 hp."
    },
    {
      "command": "play_duel",
      "when": "play",
      "args": "{ cardUid, targetSeat }",
      "actionId": "duel:<cardUid>:<targetSeat>",
      "note": "Duel any player (no range limit)."
    },
    {
      "command": "play_steal",
      "when": "play",
      "args": "{ cardUid, targetSeat, pick: { zone: \"hand\" | \"inPlay\" | \"weapon\", cardUid? } }",
      "actionId": "steal:<cardUid>:<targetSeat>:<hand|inPlay:<uid>|weapon>",
      "note": "Snatch at distance 1. zone \"hand\" takes a random hand card."
    },
    {
      "command": "play_discard_any",
      "when": "play",
      "args": "{ cardUid, targetSeat, pick }",
      "actionId": "discard_any:<cardUid>:<targetSeat>:<…>",
      "note": "Toss: discard a card of any player (random if from hand)."
    },
    {
      "command": "play_draw",
      "when": "play",
      "args": "{ cardUid }",
      "actionId": "draw:<cardUid>",
      "note": "Wagon (draw 2) or Caravan (draw 3)."
    },
    {
      "command": "play_market",
      "when": "play",
      "args": "{ cardUid }",
      "actionId": "market:<cardUid>",
      "note": "Bazaar: every living player draws 1, starting with you."
    },
    {
      "command": "play_heal_all",
      "when": "play",
      "args": "{ cardUid }",
      "actionId": "heal_all:<cardUid>",
      "note": "Saloon: every living player heals 1 (not above max)."
    },
    {
      "command": "play_heal_self",
      "when": "play (hp < maxHp) or reaction (hp == 1 and living > 2)",
      "args": "{ cardUid }",
      "actionId": "heal:<cardUid>",
      "note": "Flask: heal 1."
    },
    {
      "command": "play_equip_blue",
      "when": "play",
      "args": "{ cardUid, targetSeat? }",
      "actionId": "equip_blue:<cardUid>[:<targetSeat>]",
      "note": "Put a blue card in play: Cover / Horse / Scope / Dynamite on yourself; Jail on another seat (not the Marshal, not already jailed)."
    },
    {
      "command": "play_weapon",
      "when": "play",
      "args": "{ cardUid }",
      "actionId": "weapon:<cardUid>",
      "note": "Equip a weapon; the previous one is discarded."
    },
    {
      "command": "end_play",
      "when": "play",
      "args": "{}",
      "actionId": "end_play",
      "note": "End the play phase (then discard down to hp if needed)."
    },
    {
      "command": "discard",
      "when": "discard",
      "args": "{ cardUids: string[] }",
      "actionId": "discard",
      "note": "Discard down to hp. argsSchema.cardUids is a default; you may send args.cardUids with the same count of your own hand uids."
    },
    {
      "command": "play_miss",
      "when": "reaction (Shot / Buckshot at you)",
      "args": "{ cardUid, playedAs? }",
      "actionId": "miss:<cardUid>",
      "note": "Ricochet: cancel the hit (Double Barrel needs 2)."
    },
    {
      "command": "play_raid_discard_shot",
      "when": "reaction (Raid)",
      "args": "{ cardUid, playedAs? }",
      "actionId": "raid_discard_shot:<cardUid>",
      "note": "Answer a Raid with a Shot card."
    },
    {
      "command": "play_duel_discard_shot",
      "when": "reaction (Duel, your turn to answer)",
      "args": "{ cardUid, playedAs? }",
      "actionId": "duel_discard_shot:<cardUid>",
      "note": "Keep the Duel going with a Shot card."
    },
    {
      "command": "pass_reaction",
      "when": "reaction",
      "args": "{}",
      "actionId": "pass_reaction",
      "note": "Take the hit / lose the Raid or Duel step (−1 hp)."
    },
    {
      "command": "choose_first_draw",
      "when": "pending choice (Grip, Vulture Jr.)",
      "args": "{ choiceId, source: { kind: \"deck\" | \"hand\" | \"discard\", seat? } }",
      "actionId": "one per source (deck first)",
      "note": "Take the first draw from the deck, a random hand card of a seat (Grip) or the discard top (Vulture Jr.)."
    },
    {
      "command": "choose_look_top",
      "when": "pending choice (Three Eyes)",
      "args": "{ choiceId, putBackUid }",
      "actionId": "look_top:<choiceId>:<cardUid>",
      "note": "Keep 2 of the top 3; the named card goes back on top."
    },
    {
      "command": "choose_glory",
      "when": "pending choice (a star of glory: elimination, bounty or the Marshal's last bullet)",
      "args": "{ choiceId, perk: 'range' | 'heart' | 'sight' }",
      "actionId": "glory:<choiceId>:<perk>",
      "note": "range = +1 weapon range; heart = +1 max hp and heal 1; sight = every draw look at the top 3 and keep 2 (offered once, not to characters that already own the draw step). Default on timeout: heart."
    },
    {
      "command": "choose_prayer",
      "when": "pending choice (Preacher; staged character, not dealt yet)",
      "args": "{ choiceId, pray: boolean }",
      "actionId": "prayer:<choiceId>:yes|no",
      "note": "After another seat is eliminated: pray for a 20% return with 1 hp (once per game) or decline and keep the attempt."
    },
    {
      "command": "use_peek_role",
      "when": "phase play, your turn, no pending choice (Tracker; staged character, not dealt yet)",
      "args": "{ targetSeat }",
      "actionId": "peek:<seat>",
      "note": "Learn the exact hidden role of a living seat; only you see the result. 1 use at 4–5 seats, 2 at 6–7, 3 at 8."
    },
    {
      "command": "use_discard_heal",
      "when": "phase play / discard / reaction, any seat's turn, no pending choice (Bonesetter)",
      "args": "{ cardUids: [a, b] }",
      "actionId": "discard_heal:<a>:<b>",
      "note": "Discard 2 cards to heal 1 (not above max, not from 0)."
    }
  ]
}
