Skip to main content

Examples

Complete, runnable strategies with commentary. All but the last ship with the suite as example files — copy one into your strategy folder to try it. The last is a pattern worth having even though it is not one of the shipped files.

Every example below is reproduced exactly as it ships, including the rough edges, which are called out where they matter.

Minimal

Ships as pass-only.yaml.

$schema: https://scm.kebab.sh/strat/config.json
name: pass-only
description: Minimal example that always passes.

phases:
default:
actions:
- pass

Useful as a smoke test — load it, enable it, and confirm the runner engages and passes. If this does not work, the problem is not your strategy.

Farm nuke

Ships as storm_cp.yml.

name: storm_cp

phases:
main:
priority: 100
actions:
- cast:
name: 'Tempest'
enchant: none

Three lines of behaviour: cast Tempest, unenchanted, every round. This is what a farm bot actually wants against low-health trash — no blade setup, no enchant spend, just the cheapest AOE that clears the board.

enchant: none is deliberate. Enchanting a Tempest you are throwing at a 200-health mob wastes a card you would rather keep.

There is no fallback, so a round with no Tempest in hand does nothing. Adding fallback: pass would be strictly better.

Farm with a blade

Ships as storm_cp_sm.yml.

name: storm_cp_sm

phases:
main:
priority: 100
actions:
- cast:
name: 'StormBlade'
- cast:
name: 'Mass Storm Trap'
- cast:
name: 'Tempest'
enchant: none

Order does the work. Round one has a StormBlade in hand, so it blades. Round two has no blade left to cast, the first action fails to resolve, it tries the trap, and eventually falls through to Tempest.

No condition needed — action ordering plus resolution failure gives you the sequencing for free.

Note that the first two actions omit enchant: entirely, which here means "cast plain": there is no enchant: block in this file, so the round-start auto pass has no policy and does nothing.

Boss and mob in one file

Ships as storm_quest.yml.

name: storm_quest

clients:
- p1

phases:
boss:
priority: 100
when:
boss_present: true
actions:
- cast:
name: 'StormBlade'
enchant: none
- cast:
name: 'Tempest'
enchant: none
mob:
priority: 50
when:
boss_present: false
actions:
- cast:
name: 'Tempest'
enchant: none

Blade only when there is a boss worth blading for; otherwise go straight to the AOE. Scoped to p1, so on the console a second hooked client is left alone — on the desktop app clients: is ignored, and the strategy runs wherever you point it.

The two boss_present phases between them do not cover every round: if the enemy list cannot be read, both are false and nothing runs. There is no fallback: here either, so such a round does nothing at all. Adding fallback: pass would be strictly better.

Storm hitter

Ships as storm-hitter.yaml.

$schema: https://scm.kebab.sh/strat/config.json
name: storm-hitter
description: Example storm hitter for a secondary window.
school: storm

clients:
- p2

enchant:
prefer: epic
fallback: colossal
auto: true

targets:
default_enemy: boss
default_ally: self

fallback: pass

phases:
setup:
priority: 50
when:
no_blade: storm
actions:
- blade:
school: storm
target: self

execute:
priority: 10
actions:
- cast:
type: damage
school: storm
aoe: true
min_pips: 4
enchant: required
- cast:
type: damage
school: storm
target: boss
- wand_hit:
target: first

A proper hitter. no_blade: storm at priority 50 means it blades once and stops — as soon as a storm blade is on the board the setup phase stops matching and execute takes over.

The execute list is ordered by value: an enchanted AOE of at least 4 pips first, then any storm damage at the boss, then a wand hit. enchant: required on the first means it only fires when it can be buffed; otherwise the plain single-target spell goes out.

This file uses the legacy top-level prefer/fallback rather than a damage: block, which is what makes both auto: true and the enchant: required action work — with a blade:-only policy neither would have anything to reach for.

fallback: pass covers the round where nothing at all resolves.

Balance support

Ships as balance-support.yaml.

$schema: https://scm.kebab.sh/strat/config.json
name: balance-support
description: Example support strategy shared by two windows.
school: balance

clients:
- p1
- p3

targets:
default_enemy: boss
default_ally: lowest_health_ally

fallback: pass

phases:
emergency:
priority: 100
when:
any_ally_health_below: 35
actions:
- heal:
school: life
target: lowest_health_ally
- pass

support:
priority: 50
when:
no_blade: true
actions:
- blade:
school: balance
target: self

pressure:
priority: 10
actions:
- trap:
school: balance
target: boss
- cast:
type: damage
school: balance
target: boss
- pass

Three tiers. The emergency phase ends in pass — if someone is below 35% and there is no heal in hand, this deliberately does nothing rather than falling through to attack. That is a real choice: at 35% you would rather not pull more aggro.

"Ally" includes you, so any_ally_health_below: 35 also fires on your own health, and lowest_health_ally will pick you if you are the most hurt. For a support character that is the behaviour you want.

Scoped to two clients that both run the same behaviour, which is the case where a shared strategy beats a team file — on the console, at least; the desktop app ignores clients:.

Shadow-mutated nuke

Ships as storm.yml. The only shipped example that uses an enchant chain.

name: storm

clients:
- p1

enchant:
damage:
prefer: epic
mutation:
prefer: shadow
blade:
prefer: sharpen
trap:
prefer: potent

phases:
boss:
priority: 100
when:
all:
- boss_present: true
- round_above: 1
actions:
- blade:
target: self
school: storm
enchant: required
- cast:
name: 'Glowbug Squall'
enchant: required
enchants:
- type: mutation
- type: damage
when:
shadow_pips_above: 0

main:
priority: 100
actions:
- blade:
target: self
school: storm
enchant: required
when:
no_blade:
target: self
school: storm
enchanted: true
- blade:
target: self
school: storm
enchant: none
when:
no_blade:
target: self
school: storm
enchanted: false
- cast:
name: 'Frenzy'
enchant: none
- cast:
name: 'Storm Lord'
enchant: required
- cast:
name: 'Bunyip'
enchant: required

The chain is the interesting part. Neither step names a card, so each one takes its prefer from the matching policy: type: mutation pulls shadow, type: damage pulls epic. The mutation lands first, then the damage enchant goes on top of it — a second step is allowed to enchant an already-enchanted card, which the single-policy path is not.

The main phase is a good model for blade layering: sharpened blade first, plain blade only once the sharpened one is down, each guarded on the board rather than on a round counter.

This file relies on the priority tiebreak

boss and main both sit at priority 100. They only resolve in that order because boss sorts before main alphabetically. Rename the phases and the behaviour changes. Give the boss phase a higher number instead — this is exactly the mistake Phases → priority warns about.

Non-healing support

Ships as blade-fire.yaml.

$schema: https://scm.kebab.sh/strat/config.json
name: blade-fire
description: Non-healing support example that buffs p1 directly.
school: balance

clients:
- p2

enchant:
blade:
prefer: sharpen
trap:
prefer: potent

targets:
default_ally: p1
default_enemy: boss

fallback: pass

phases:
main:
priority: 75
actions:
- cast:
name: Fire Blade
target: p1
enchant: required
- blade:
school: balance
target: p1
enchant: required
- trap:
school: balance
target: boss
- pass

A balance character buffing a fire hitter. The action list is a priority order: the fire blade is worth more to a fire hitter than a balance blade, so it goes first; the balance blade is the fallback; the trap is what happens when both blades are already down.

The enchant.blade policy is what makes the second action's enchant: required produce a sharpened blade rather than whatever enchant happened to be nearest. The trap: policy is inert here — the trap action carries no enchant: key, so nothing ever consults it.

Two things to fix before you copy this one

The first action never fires as written. cast: picks its enchant policy from the spell type of the card it matched, and Fire Blade is a charm — so it looks for enchant.support, not enchant.blade. There is no support: block here, no top-level prefer, and no enchants: chain, so enchant: required has nothing to reach for and the action is skipped every round. The blade: action below it works, because blade: does consult enchant.blade.

Add support: { prefer: sharpen } to the enchant: block, or spell the chain out on the action:

- cast:
name: Fire Blade
target: p1
enchant: required
enchants:
- prefer: sharpen

It is console-only. target: p1 and default_ally: p1 do not resolve in the desktop app, so both blade actions are skipped there and the strategy degrades to "trap the boss, then pass". See Targeting → client aliases.

Boss and mob split

Not a shipped file, but the pattern is worth having:

$schema: https://scm.kebab.sh/strat/config.json
name: fire-adaptive
school: fire

targets:
default_enemy: boss

enchant:
damage: { prefer: epic, fallback: colossal }
blade: { prefer: sharpen }

fallback: pass

phases:
emergency:
priority: 200
when:
health_below: 30
actions:
- heal: { school: life, target: self }

boss-setup:
priority: 120
when:
all:
- boss_present: true
- no_blade: fire
actions:
- blade: { school: fire, target: self, enchant: required }

boss-hit:
priority: 100
when:
boss_present: true
actions:
- cast: { name: 'Fire Dragon', enchant: required }
- cast: { type: damage, school: fire, target: boss }

mob-clear:
priority: 50
when:
all:
- boss_present: false
- enemies_at_least: 2
actions:
- cast: { type: damage, school: fire, aoe: true, enchant: none }

single:
priority: 10
actions:
- cast: { type: damage, school: fire }
- wand_hit: { target: first }

Blades and enchants only get spent on boss fights. Trash gets an unenchanted AOE, and anything else falls through to a plain hit. The emergency heal sits above everything at 200 and, having no trailing pass, falls through to normal play when no heal is in hand.

The blade: policy is not optional here. enchant: required on the boss-setup blade needs enchant.blade (or enchant.support, or a top-level prefer) to have anything to reach for — a damage:-only policy would leave that action permanently skipped.

Team

See Teams for life_fire.yml, a two-character strategy where a life support character lays sharpened blades and potent feints for a fire hitter.