| name | gdtoolkit |
| description | Lint and format GDScript files using gdtoolkit (gdlint + gdformat).
Use after writing or modifying .gd files, when asked to check code style,
fix lint errors, format code, or set up linting configuration.
Also use when gdlint/gdformat errors appear in output and need diagnosis.
Does NOT require Godot — runs as a standalone Python tool.
|
gdtoolkit — GDScript Lint & Format
Currently disabled (v0.3.4+). gm-verify no longer invokes
gdlint / gdformat, and gm-build / gm-fixgap have removed this
skill from their Available Skills tables. Reason: repeated
gdtoolkit/linter/class_checks.py:144 NotImplementedError crashes on
common ECS-style GDScript class shapes, plus low signal-to-noise vs
the headless compile + reviewer pattern checks. Re-enabling tracked as
ROADMAP R-112. The reference content below is preserved for ad-hoc
use outside the pipeline and for the future re-enablement.
Wraps two CLI tools from the gdtoolkit Python package:
- gdlint — static analysis and style checking
- gdformat — deterministic auto-formatter
Prerequisites
pip install "gdtoolkit==4.*"
pip install "gdtoolkit==3.*"
Verify installation: gdlint --version && gdformat --version
If not installed, tell the user and offer to install. The version major must match
the project's Godot major version (read from project.godot config/features).
Lint workflow
Run gdlint
gdlint path/to/file.gd
gdlint path/to/directory/
Interpret output
Each problem is one line on stderr:
path/to/file.gd:42: Error: Function name "MyFunc" is not valid (function-name)
Format: {file}:{line}: Error: {message} ({rule-id})
Exit codes:
- 0 — no problems (stdout:
Success: no problems found)
- 1 — problems found (stderr:
Failure: N problem(s) found)
Fix lint issues
For each reported issue, either:
- Fix the code — rename to match convention, remove unused arg, reorder members
- Suppress inline — when the violation is intentional:
# gdlint:ignore = rule-id
var _unusedButNeeded := 0 # this line + next line are suppressed
- Suppress region — for larger blocks:
# gdlint: disable=function-name
func ALLCAPS_required_by_engine():
pass
# gdlint: enable=function-name
When suppressing, always add a brief comment explaining why.
Format workflow
Run gdformat
gdformat path/to/file.gd
gdformat path/to/directory/
gdformat --check path/
gdformat --diff path/
Exit codes:
- 0 — already formatted / formatting succeeded
- 1 — check mode found differences / parse error / safety check failed
Safety checks
gdformat runs three safety checks by default (disable with --fast):
- TreeInvariantViolation — parse tree changed after formatting
- FormattingStabilityViolation — formatting isn't idempotent
- CommentPersistenceViolation — comments were lost
If a safety check fails, report the error to the user — do NOT use --fast to bypass it.
This likely indicates a gdtoolkit bug; the file should be formatted manually or the
problematic section excluded.
Rule reference
Naming rules (regex-configurable)
| Rule ID | Default convention | Example |
|---|
function-name | snake_case or _on_PascalCase_signal | move_player, _on_Button_pressed |
class-name | PascalCase | PlayerController |
sub-class-name | _PascalCase (leading underscore) | _InternalHelper |
signal-name | snake_case | health_changed |
class-variable-name | snake_case or _private | speed, _cache |
function-variable-name | snake_case | local_var |
function-argument-name | snake_case or _unused | target_pos, _ignored |
loop-variable-name | snake_case or _unused | item, _i |
constant-name | UPPER_SNAKE_CASE | MAX_SPEED |
enum-name | PascalCase | Direction |
enum-element-name | UPPER_SNAKE_CASE | NORTH, SOUTH_EAST |
Code quality rules
| Rule ID | Default | What it checks |
|---|
max-returns | 6 | Too many return statements per function |
max-public-methods | 20 | Too many public methods per class |
function-arguments-number | 10 | Too many function arguments |
max-file-lines | 1000 | File too long |
max-line-length | 100 | Line too long |
Style rules
| Rule ID | What it checks |
|---|
unnecessary-pass | pass in non-empty body |
duplicated-load | Same resource loaded twice |
expression-not-assigned | Standalone expression with no effect |
unused-argument | Argument never used (fix: prefix with _) |
comparison-with-itself | x == x |
private-method-call | Calling _private_method() from outside |
class-definitions-order | Members not in canonical order (see below) |
trailing-whitespace | Trailing spaces |
mixed-tabs-and-spaces | Mixed indentation |
no-elif-return | Unnecessary elif after return |
no-else-return | Unnecessary else after return |
Class member order (class-definitions-order)
gdlint expects this top-to-bottom order:
@tool
class_name
extends
- Docstring
- Signals
- Enums
- Constants
- Static variables
@export variables
- Public variables
- Private variables (
_prefixed)
@onready public variables
@onready private variables
- Remaining declarations
Configuration
gdlintrc
Create .gdlintrc (or gdlintrc) in the project root. YAML format.
gdlint searches upward from CWD, uses the first file found.
Generate defaults: gdlint -d > .gdlintrc
Example with customizations:
max-line-length: 120
function-name: '(_on_[A-Z][a-z0-9]*(_[a-z0-9]+)*|[a-z][a-z0-9]*(_[a-z0-9]+)*)'
disable:
- unnecessary-pass
excluded_directories: !!set
.git: null
addons: null
.godot: null
gdformatrc
Create gdformatrc in the project root. YAML format.
Generate defaults: gdformat --dump-default-config > gdformatrc
line_length: 120
excluded_directories: !!set
.git: null
addons: null
.godot: null
Important: no pyproject.toml support
gdtoolkit does NOT read from pyproject.toml. Only its own YAML config files work.
Recommended: align line lengths
Set max-line-length in .gdlintrc and line_length in gdformatrc to the same
value. If they differ, gdformat may merge lines that then exceed gdlint's limit —
a known source of false positives.
Quirks and limitations
-
No # gdformat: off/on — there is no way to skip formatting for a code region.
If gdformat mangles a specific construct, the only workaround is to restructure the code.
-
gdlint checks unused arguments, not unused variables — var x = 1 with no
further use of x will NOT be flagged. Only function arguments trigger unused-argument.
-
excluded_directories only works when scanning directories — passing a file path
directly (gdlint addons/plugin/main.gd) bypasses exclusion rules.
-
gdformat safety check failures are real bugs — do not silence them with --fast.
Report to the user and format that section manually.
-
gdformat may cause data loss — always ensure the file is under version control
before formatting. Run git diff after formatting to verify changes are correct.
-
Version must match Godot version — gdtoolkit 4.x parses Godot 4 syntax,
3.x parses Godot 3. Mismatched versions cause parse errors on valid code.
Fallback: upstream documentation
If this skill's instructions don't resolve your issue — unexpected output, unfamiliar
rule IDs, config syntax errors, or parse failures — consult the upstream repo directly:
Use WebFetch to read the wiki pages or issue threads when you need details beyond
what this skill covers.