Team Validation
Before a battle starts, Frontier checks every team against the ladder’s format rules. Species bans, move restrictions, custom MoLang logic — it all runs through the clause system. Illegal teams can’t queue.
When Validation Runs
Section titled “When Validation Runs”Clauses are enforced at three different points, depending on their type:
- Queue join —
TEAM_VALIDATIONclauses run against the player’s team. Fail any clause and you can’t join the queue. The failure message tells you exactly what’s wrong. - Battle start —
SHOWDOWN_NATIVEclauses are passed to the Showdown engine as rule strings. Format-level bans (species, moves, abilities, items) are also applied here. - During battle —
IN_BATTLEclauses fire when players attempt to use banned mechanics (Mega Evolution, Terastallization, etc.).
Three Clause Types
Section titled “Three Clause Types”| Type | When it runs | How it works |
|---|---|---|
TEAM_VALIDATION | Queue join + battle start | Custom MoLang expressions evaluated against the team. |
SHOWDOWN_NATIVE | Battle start | Rule string passed directly to the Showdown battle engine. |
IN_BATTLE | During battle | Frontier intercepts banned battle mechanics (gimmick bans). |
Clause Structure
Section titled “Clause Structure”Clauses live in config/frontier/clauses.conf. Here’s an example:
clauses { species_clause { displayName = "Species Clause" description = "A player cannot have two of the same species on their team." type = "TEAM_VALIDATION" showdownRule = "Species Clause" perPokemon = false molangExpression = ["!query.has_duplicate_species"] failureMessage = "Species Clause: Your team has duplicate species" }}| Field | Type | Default | Description |
|---|---|---|---|
displayName | String | "" | Human-readable name shown in GUIs. |
description | String | "" | What the clause does, shown in format info. |
type | ClauseType | "SHOWDOWN_NATIVE" | When and how the clause runs. |
showdownRule | String? | null | Showdown rule string (only for SHOWDOWN_NATIVE clauses). |
molangExpression | List | null | MoLang expressions for validation. Each entry is a separate expression. |
perPokemon | Boolean | true | If true, expression runs once per Pokemon. If false, once for the whole team. |
failureMessage | String? | null | Message shown when validation fails. Supports {pokemon} (per-Pokemon only) and {clause} placeholders. |
Format-Level Bans
Section titled “Format-Level Bans”Beyond clauses, formats can ban specific species, moves, abilities, and items directly. These are configured in config/frontier/formats.conf:
formats { ou { displayName = "OU" clauses = ["species_clause", "sleep_clause", "evasion_clause", "ohko_clause"] bannedSpecies = ["mewtwo", "arceus", "zacian"] bannedMoves = ["swagger", "baton_pass"] bannedAbilities = ["moody", "shadow_tag"] bannedItems = ["kings_rock"] validateLegality = true }}| Field | Type | Default | Description |
|---|---|---|---|
bannedSpecies | List | [] | Species to ban (Showdown IDs, e.g. "mewtwo", "arceus"). |
bannedMoves | List | [] | Moves to ban (e.g. "swagger", "baton_pass"). |
bannedAbilities | List | [] | Abilities to ban (e.g. "moody", "shadow_tag"). |
bannedItems | List | [] | Items to ban (e.g. "kings_rock"). |
validateLegality | Boolean | false | Check each Pokemon’s moves and abilities against its species/form for legality. |
Formats also support inheritance with the includes field — ban lists and clauses merge from all included formats:
formats { base_ou { clauses = ["species_clause", "sleep_clause", "evasion_clause", "ohko_clause"] bannedSpecies = ["mewtwo", "arceus", "zacian"] validateLegality = true } ou_no_tera { displayName = "OU (No Tera)" includes = ["base_ou"] clauses = ["ban_tera"] }}Built-In Clauses
Section titled “Built-In Clauses”Team Validation Clauses
Section titled “Team Validation Clauses”| ID | Name | Per-Pokemon | Description |
|---|---|---|---|
species_clause | Species Clause | No | No duplicate species on a team. |
item_clause | Item Clause | No | No duplicate held items on a team. |
evasion_clause | Evasion Clause | Yes | Bans Double Team and Minimize. |
ohko_clause | OHKO Clause | Yes | Bans Fissure, Sheer Cold, Horn Drill, Guillotine. |
monotype | Monotype | No | All team members must share a type. |
level_cap | Level Cap | Yes | Pokemon must be at or below the format’s target level. |
no_legendaries | No Legendaries | Yes | Legendary Pokemon are banned. |
nfe_only | NFE Only | Yes | Only unevolved Pokemon (Little Cup). |
Showdown Native Clauses
Section titled “Showdown Native Clauses”| ID | Name | Showdown Rule | Description |
|---|---|---|---|
sleep_clause | Sleep Clause | "Sleep Clause Mod" | Only one opposing Pokemon can be asleep at a time. |
In-Battle Clauses (Gimmick Bans)
Section titled “In-Battle Clauses (Gimmick Bans)”| ID | Name | What it bans |
|---|---|---|
gimmick_ban | Gimmick Ban | Mega Evolution, Ultra Burst, Z-Moves, Dynamax, Terastallization |
ban_mega | Mega Evolution Ban | Mega Evolution, Ultra Burst |
ban_tera | Terastallization Ban | Terastallization |
ban_dynamax | Dynamax Ban | Dynamax |
ban_zmoves | Z-Moves Ban | Z-Moves |
MoLang Query API
Section titled “MoLang Query API”Frontier exposes MoLang queries for writing custom clause expressions.
Per-Pokemon Queries
Section titled “Per-Pokemon Queries”Available when perPokemon = true. Access through query.pokemon.
| Query | Returns | Description |
|---|---|---|
query.pokemon.level | Double | Pokemon’s current level. |
query.pokemon.can_evolve | 1.0/0.0 | Whether the Pokemon can still evolve. |
query.pokemon.has_move('name') | 1.0/0.0 | Whether the Pokemon knows a specific move (Showdown ID). |
query.pokemon.has_any_move('m1,m2,...') | 1.0/0.0 | Whether the Pokemon knows any of the listed moves (comma-separated). |
query.pokemon.species.has_label('label') | 1.0/0.0 | Whether the species has a label (e.g., legendary). |
query.pokemon.ability.name | String | The Pokemon’s ability (Showdown ID). |
Team-Wide Queries
Section titled “Team-Wide Queries”Available in both per-Pokemon and team mode.
| Query | Returns | Description |
|---|---|---|
query.team_size | Double | Number of Pokemon on the team. |
query.has_duplicate_species | 1.0/0.0 | Whether the team has duplicate species. |
query.has_duplicate_items | 1.0/0.0 | Whether the team has duplicate held items. |
query.team_shares_type | 1.0/0.0 | Whether all team members share at least one type. |
query.format_target_level | Double | Format’s target level (0 if none set). |
query.format_team_size | Double | Format’s max team size. |
Custom Clause Examples
Section titled “Custom Clause Examples”Ban specific abilities
Section titled “Ban specific abilities”clauses { no_uber_abilities { displayName = "No Uber Abilities" description = "Bans Shadow Tag and Arena Trap." type = "TEAM_VALIDATION" perPokemon = true molangExpression = [ "query.pokemon.ability.name != 'shadowtag' && query.pokemon.ability.name != 'arenatrap'" ] failureMessage = "{pokemon} has a banned ability" }}Level 50 cap
Section titled “Level 50 cap”clauses { max_level_50 { displayName = "Level 50 Cap" description = "All Pokemon must be level 50 or below." type = "TEAM_VALIDATION" perPokemon = true molangExpression = ["query.pokemon.level <= 50"] failureMessage = "{pokemon} exceeds the level 50 cap" }}