Skip to content

Skill File Structure

Previous: Core Concepts · Next: Skill Definition: All Fields

This page covers where the files live, how the directories are split, and what each bundled example teaches — aimed at those who are "ready to start configuring skills but haven't written the first line yet." By the end you'll know: how many files make up a skill, which folder each goes in, and how to make your changes take effect.

No programming background required — just match your files to the directory structure.

🖼️ [Image placeholder] A screenshot of the expanded plugins/QinhSkills/ directory tree, highlighting the two directory sets skills/ and graphs/ · suggested assets/file-layout-tree.png


📁 One skill = two files

In QS, a complete skill consists of two YAML files, placed in two separate directories:

FileLocationResponsibility
Skill definitionplugins/QinhSkills/skills/<category>/xxx.ymlWhat the skill "is": trigger key, cooldown, target, cost, levels…
graph (execution graph)plugins/QinhSkills/graphs/<category>/xxx.graph.ymlHow the skill "flows": which key routes to which node, which MM skill to fire, combos

💡 Why split into two? A simple skill really only uses one "entry node" in the graph, which you'll hardly ever touch. But the moment you build a combo, the graph is where the multi-stage logic lives — by separating out the "key routing," the skill definition file stays clean. See graph & combos for details.

The two files are linked by a single name, and it must be identical in four places: graph.entry in the skill definition == the graph file's graph_id == the graph file's entry == the entry node's name.

yaml
# skills/combat/fire_wave.yml
graph:
  entry: fire_wave        # ← points to the graph below

# graphs/combat/fire_wave.graph.yml
graph_id: fire_wave       # ← ① must match
entry: fire_wave          # ← ② the entry node name must match too
nodes:
  fire_wave:              # ← ③ the entry node's node_id must match as well
    ...

🗂️ Five fixed categories

Both skills/ and graphs/ contain the same five fixed category folders. Which folder a skill goes in is determined by its meta.category, and the two must agree:

CategoryPurposeTypical skills
combatCombat / damage / melee & rangedFire wave, blade slash, retaliate
movementMobility / dodgedash
utilityBuffs / shields / toolsshield
bossBoss-only skills(build your own as needed)
comboCombo skillsfire combo dance
text
plugins/QinhSkills/
├── skills/
│   ├── combat/      fire_wave.yml  blade_slash.yml  retaliate.yml  …
│   ├── movement/    dash.yml
│   ├── utility/     shield.yml
│   ├── boss/
│   └── combo/       fire_combo_finisher.yml
└── graphs/
    ├── combat/      fire_wave.graph.yml  blade_slash.graph.yml  …
    ├── movement/    dash.graph.yml
    ├── utility/     shield.graph.yml
    ├── boss/
    └── combo/       fire_combo_finisher.graph.yml

⚠️ A skill file and its graph go under the same-named category. A combat skill's graph goes in graphs/combat/. The category only affects organization and display, not functionality, but getting meta.category wrong will raise a schema warning on /qs reload.

💡 All five categories are valid (combat / movement / utility / combo / boss — the source enum does include BOSS), but there's no boss skill among the bundled examples — the boss/ directory in the table above is one you create yourself; just set meta.category to boss for any boss skill you put there.


🎓 Bundled examples: editing one is the fastest way

💡 The quickest way to get started: just look at the bundled examples. On first launch, QS drops a set of heavily commented tutorial examples under skills/, each ready to use out of the box — just edit and go.

Example fileWhat it teachesDifficulty
combat/fire_waveThe most basic template, read this first — what a castable active skill looks like
combat/blade_slashAuto-targeting + health cost + GCD + cast conditions + ready notify + conflict group⭐⭐⭐
combat/demo_slashTriggered by a QinhItems item key⭐⭐
combat/demo_slash_chargedChanneled cast bar (charge-up bar)⭐⭐⭐
combat/retaliatePassive counterattack (auto-triggered on taking damage)⭐⭐
movement/dashCharge stacks + GCD-exempt⭐⭐⭐
utility/shieldToggle-style skill⭐⭐
combo/fire_combo_finisherCombo: Right → Right → Left⭐⭐⭐⭐

Suggested reading order: start with fire_wave (to understand "the skeleton of a skill") → then blade_slash (to learn advanced gating) → only look at fire_combo_finisher once you want to build a combo.

🔒 Default skill files are only dropped when missing; they never overwrite your changes. If you've edited fire_wave.yml, restarting QS won't revert it. To restore the factory example, delete the file and run /qs reload.

💬 By default each example only sends a single [QinhSkills] <skill name> confirmation message. For real fire / damage / particles, just write a same-named MM skill in plugins/MythicMobs/skills/ — when QS finds you already have a same-named skill, it won't overwrite it. See Integrating MythicMobs for details.


📑 A skill's "two sets of fields"

Open any skill yml and the fields split into an upper and a lower half. This is a deliberate QS design, and understanding it will save you from major pitfalls.

This set of fieldsRoleWho reads it
Upper: meta / trigger / state / graph / executionEcosystem info — category filing, /qs reload consistency checks, combo-orchestration referenceschema validator
Lower: type / cooldown / resource / cast_mode / levelsWhat's actually read at runtime — determines the skill's real behaviorruntime loader

Taking fire_wave as an example, the upper and lower halves point at the same skill and must stay consistent:

yaml
# ===== Upper: ecosystem info (validated on reload) =====
meta:
  category: combat            # category, must match the folder the file is in
trigger:
  primary: RIGHT_CLICK        # primary trigger key, must be in the graph entry node's triggers
state:
  required: IDLE              # required state, must match the entry node's require_state
graph:
  entry: fire_wave            # which graph to use
execution:
  mythic_skill: fire_wave     # which MM skill to fire, must match the entry node's mythic_skill

# ===== Lower: what's actually read at runtime =====
type: active                  # ← this line is what actually decides active/passive
cooldown:
  base: 3000                  # ← the cooldown actually used at runtime

⚠️ The two sets must agree. /qs reload validates them item by item, and raises a schema warning on any mismatch (it won't crash the server, but skill behavior may not be what you expect). Common correspondences:

  • state.required ↔ entry node require_state
  • execution.mythic_skill ↔ entry node mythic_skill
  • trigger.primary ⊂ entry node triggers (the primary trigger key must be included in the node's triggers)

Why two sets? The upper set lets the validator, combo orchestration, and a future editor understand what a skill looks like without running it; the lower set is the config the engine actually consumes at runtime. One is for "understanding," the other for "executing." For the full field reference, see Skill Definition: All Fields.


🏷️ Naming rules

RuleExplanation
Skill id is all lowercaseid defaults to the filename (minus .yml); we suggest just using the filename as the id
Same name in four placesA skill's graph.entry = graph graph_id = graph entry = entry node name; all four must be identical
graph file suffixThe graph file must end in .graph.yml, otherwise it isn't recognized as a graph
References elsewhere all use the idWhen items, combos, and commands reference a skill, they all use the skill id (not the display name)
MM skill same nameThe MM skill that execution.mythic_skill points to should share the skill's id, to save you from tracking two names

For example, a combat skill with id fire_wave has this standard trio:

text
skills/combat/fire_wave.yml         # id: fire_wave
graphs/combat/fire_wave.graph.yml   # graph_id: fire_wave, entry: fire_wave
MythicMobs/skills/... (skill named fire_wave)   # the real effect you write yourself

🔄 Making changes take effect (the reload loop)

Edited files don't take effect automatically — you have to reload manually. Remember these three correspondences:

What you editedWhat command to run
Skill definition skills/**.yml/qs reload
graph file graphs/**.graph.yml/qs reload
MythicMobs skill file/mm reload
text
# After editing a skill or graph
/qs reload

# After editing the real effect on the MM side
/mm reload

💡 /qs reload does three things: it reloads skill definitions + graphs + routing, and syncs the MM bridge. It also runs the "two sets of fields consistency check" mentioned above — after reloading, watch the console for schema warnings.

⚠️ Changes to MM skills (particles / damage / mobility) are handled by /mm reload; /qs reload won't reload MythicMobs for you. Each side manages its own.


✅ Summary

  • A skill = skills/<category>/xxx.yml (definition) + graphs/<category>/xxx.graph.yml (execution graph), linked by graph.entry = graph_id = graph entry = entry node name (same name in four places).
  • Five fixed categories: combat / movement / utility / boss / combo.
  • Bundled examples are only dropped when missing and never overwrite your changes — start reading from fire_wave.
  • A skill yml's upper and lower field sets (ecosystem validation vs runtime read) must stay consistent, and are validated on reload.
  • Edit a skill / graph → /qs reload; edit MM → /mm reload.

Keep reading