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 setsskills/andgraphs/· suggestedassets/file-layout-tree.png
📁 One skill = two files
In QS, a complete skill consists of two YAML files, placed in two separate directories:
| File | Location | Responsibility |
|---|---|---|
| Skill definition | plugins/QinhSkills/skills/<category>/xxx.yml | What the skill "is": trigger key, cooldown, target, cost, levels… |
| graph (execution graph) | plugins/QinhSkills/graphs/<category>/xxx.graph.yml | How 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.
# 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:
| Category | Purpose | Typical skills |
|---|---|---|
combat | Combat / damage / melee & ranged | Fire wave, blade slash, retaliate |
movement | Mobility / dodge | dash |
utility | Buffs / shields / tools | shield |
boss | Boss-only skills | (build your own as needed) |
combo | Combo skills | fire combo dance |
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
combatskill's graph goes ingraphs/combat/. The category only affects organization and display, not functionality, but gettingmeta.categorywrong will raise a schema warning on/qs reload.💡 All five categories are valid (
combat/movement/utility/combo/boss— the source enum does includeBOSS), but there's no boss skill among the bundled examples — theboss/directory in the table above is one you create yourself; just setmeta.categorytobossfor 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 file | What it teaches | Difficulty |
|---|---|---|
combat/fire_wave | The most basic template, read this first — what a castable active skill looks like | ⭐ |
combat/blade_slash | Auto-targeting + health cost + GCD + cast conditions + ready notify + conflict group | ⭐⭐⭐ |
combat/demo_slash | Triggered by a QinhItems item key | ⭐⭐ |
combat/demo_slash_charged | Channeled cast bar (charge-up bar) | ⭐⭐⭐ |
combat/retaliate | Passive counterattack (auto-triggered on taking damage) | ⭐⭐ |
movement/dash | Charge stacks + GCD-exempt | ⭐⭐⭐ |
utility/shield | Toggle-style skill | ⭐⭐ |
combo/fire_combo_finisher | Combo: 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 inplugins/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 fields | Role | Who reads it |
|---|---|---|
Upper: meta / trigger / state / graph / execution | Ecosystem info — category filing, /qs reload consistency checks, combo-orchestration reference | schema validator |
Lower: type / cooldown / resource / cast_mode / levels… | What's actually read at runtime — determines the skill's real behavior | runtime loader |
Taking fire_wave as an example, the upper and lower halves point at the same skill and must stay consistent:
# ===== 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 reloadvalidates 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 noderequire_stateexecution.mythic_skill↔ entry nodemythic_skilltrigger.primary⊂ entry nodetriggers(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
| Rule | Explanation |
|---|---|
| Skill id is all lowercase | id defaults to the filename (minus .yml); we suggest just using the filename as the id |
| Same name in four places | A skill's graph.entry = graph graph_id = graph entry = entry node name; all four must be identical |
| graph file suffix | The graph file must end in .graph.yml, otherwise it isn't recognized as a graph |
| References elsewhere all use the id | When items, combos, and commands reference a skill, they all use the skill id (not the display name) |
| MM skill same name | The 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:
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 edited | What command to run |
|---|---|
Skill definition skills/**.yml | /qs reload |
graph file graphs/**.graph.yml | /qs reload |
| MythicMobs skill file | /mm reload |
# After editing a skill or graph
/qs reload
# After editing the real effect on the MM side
/mm reload💡
/qs reloaddoes 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 reloadwon'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 bygraph.entry=graph_id= graphentry= 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
- Fill out a skill field by field → Skill Definition: All Fields
- Build combos / multi-stage skills → graph & combos
- Didn't grasp the rationale behind the "two sets of fields" → Core Concepts
- Attach a skill to an item → Integration Overview