Custom Rules
advanced featureCustom Rules
Beyond the three native Conventions checks, EDP exposes a power-user rule engine. Compose predicates (what an asset matches on) with recipes (what EDP does about it) to author rules specific to your project's structure.
Model
A custom rule has three parts:
- Id -
EDP-USER-<your-id>. Stable across runs; used by the suppression store and report schema. - Predicate - one of five primitives, optionally combined via Not. Asset-level predicates evaluate against every asset under the scan scope.
- Recipe - what EDP does when the predicate matches. Four primitives.
Predicates
| Predicate | Argument | Matches when |
|---|---|---|
| PathMatches | path glob | The asset path matches the glob (e.g. Assets/Plugins/**, Assets/Game/Levels/**/*.unity). |
| IsType | type name | The asset's main type is the given Unity type (Texture2D, Material, SceneAsset, Prefab, MonoScript, etc.). |
| NamePrefix | string | The asset's file name starts with the given string (e.g. T_, M_, SO_). |
| HasComponent | component type name | The asset is a prefab containing the given component type anywhere in its hierarchy. |
| Not | another predicate | Inverts a predicate. |
Recipes
| Recipe | Argument | Effect |
|---|---|---|
| Flag | severity, message | Emits a finding with the given severity and human-readable message. No fix; review-only. |
| MoveAsset | destination folder | Manual fix: prompts confirmation, then runs AssetDatabase.MoveAsset to the destination. GUID-preserving. |
| Rename | rename pattern | Manual fix: prompts confirmation, then runs AssetDatabase.RenameAsset using the pattern (the {name} placeholder expands to the current filename without extension). GUID-preserving. |
| Ignore | (none) | Skip the asset entirely from every check. Useful for project-specific exclusions that don't fit the path-glob exclude list. |
Example: keep textures out of /Prefabs
{
"id": "no-textures-under-prefabs",
"predicate": {
"kind": "and",
"left": { "kind": "PathMatches", "glob": "Assets/Prefabs/**" },
"right": { "kind": "IsType", "type": "Texture2D" }
},
"recipe": {
"kind": "MoveAsset",
"destination": "Assets/Textures"
}
}
The rule fires on every Texture2D under Assets/Prefabs/ and offers a Manual fix to move it to Assets/Textures/.
Example: flag orphan ScriptableObjects in /Game
{
"id": "no-orphan-so-in-game",
"predicate": {
"kind": "and",
"left": { "kind": "PathMatches", "glob": "Assets/Game/**" },
"right": { "kind": "IsType", "type": "ScriptableObject" }
},
"recipe": {
"kind": "Flag",
"severity": "warn",
"message": "ScriptableObject under Assets/Game/ - relocate to Assets/Game/Data/."
}
}
Storage
Custom rules live in ProjectSettings/EditorDoctorPro/user-rules.json and are shared via git. The Settings UI reads / writes this file via the inline editor under Settings > Conventions > Custom Rules; you can also edit the JSON directly and reimport.
Reversibility
Move and rename recipes use AssetDatabase.MoveAsset and AssetDatabase.RenameAsset. Both preserve the GUID, so references in scenes / prefabs / serialized data follow the asset to its new path / name. Restore the action from the Action History Trash workflow.
Suggest an improvement
Help us improve this documentation page.