Skip to main content

A CLI auditor for Godot 4 projects

Project description

godot-project-doctor

English | 한국어

PyPI version PyPI downloads License: MIT CI

A deterministic CLI auditor for Godot 4 projects.

godot-project-doctor scans a Godot project folder, parses project metadata and resource references, detects common issues, and generates human-readable and machine-readable reports for CI pipelines and AI agents.

Not an AI tool. Pure static analysis — no LLM calls, no network requests. Perfect for GitHub Actions, linters, and AI coding workflows.


What it detects

Category Issues
Structural Circular dependency cycles, missing main scene, missing autoloads
References Missing external resources (scenes, scripts, textures), broken uid:// paths
Scripts Undefined input actions, broken signal connections, unused scripts
Assets Unused scripts/autoloads, unused asset candidates, oversized textures/audio

v0.8.0 additions: Full uid:// resolution (sidecar + import + cache), SARIF 2.1.0 output, GitHub Action, config-driven severity overrides, unused-script detection.


Installation

pip install godot-project-doctor

Optional: For texture-size checks, add Pillow:

pip install "godot-project-doctor[image]"

Quick start

gdoctor scan ./my-game

Output (text mode, ANSI-safe on Windows CP949):

ERROR    MISSING_MAIN_SCENE          project.godot: run/main_scene = res://scenes/Main.tscn (file not found)
ERROR    CIRCULAR_DEPENDENCY         scenes/Player.tscn → scenes/Level.tscn → scenes/Player.tscn
WARNING  BROKEN_SIGNAL_CONNECTION    scenes/UI.tscn:[connection] signal=pressed method=_on_clicked (not found in target script)
WARNING  UNUSED_SCRIPT               player/old_controller.gd (not referenced by any scene/autoload)
INFO     NO_EXPORT_PRESETS           export_presets.cfg not found

Scanned 12 scenes, 18 scripts. 2 errors, 2 warnings, 1 info.

Usage

scan — audit for issues

gdoctor scan <project_path> [--format text|json|markdown|sarif] [--output <path>]
              [--fail-on error|warning|info|none] [--strict]
              [--config <path>] [--no-config] [--include-addons]
# Human-readable terminal report
gdoctor scan ./my-godot-game

# JSON report for CI or AI agents
gdoctor scan ./my-godot-game --format json --output report.json

# Markdown report
gdoctor scan ./my-godot-game --format markdown --output report.md

# Fail CI on any WARNING or higher (default: ERROR only)
gdoctor scan ./my-godot-game --strict

# Suppress exit code entirely (always exits 0)
gdoctor scan ./my-godot-game --fail-on none

# Also audit third-party plugin code under res://addons/
gdoctor scan ./my-godot-game --include-addons

# Use an explicit config file
gdoctor scan ./my-godot-game --config ci-strict.toml

addons/ is ignored by default. Third-party plugin code under res://addons/ and res://script_templates/ is excluded, because it is loaded by the editor or referenced by class_name and would otherwise drown real findings in false positives. Pass --include-addons (or set ignore_addons = false) to audit it too.

Configuration file

gdoctor reads configuration from one of two places:

  • pyproject.toml — under a [tool.gdoctor] table (keys are namespaced).
  • .gdoctor.toml (project root) or --config <path> — keys live at the root of the file, with no [tool.gdoctor] prefix.

Use --no-config to ignore all config files.

# pyproject.toml  →  namespaced under [tool.gdoctor]
[tool.gdoctor]
large_texture_dim  = 1024          # warn on textures > 1024 px (default 2048)
large_audio_bytes  = 5_242_880     # warn on audio > 5 MB (default 10 MB)
ignore             = ["assets/vendor/**", "*.tmp.gd"]
ignore_addons      = true          # exclude addons/ & script_templates/ (default)

[tool.gdoctor.severity]
UNUSED_ASSET_CANDIDATE = "info"    # downgrade to INFO
NO_EXPORT_PRESETS      = "none"    # suppress entirely

[[tool.gdoctor.baseline]]
code    = "MISSING_EXT_RESOURCE"
file    = "scenes/legacy/Old.tscn"
message = "External resource not found: res://legacy/old.gd"
# .gdoctor.toml  →  same keys, but at the root (no [tool.gdoctor])
large_texture_dim = 1024
ignore            = ["assets/vendor/**"]

[severity]
UNUSED_ASSET_CANDIDATE = "info"

graph — dependency graph

gdoctor graph <project_path> [--format text|mermaid] [--output <path>]

Builds a directed graph of source_file → referenced_resource edges from all parsed .tscn, .tres, and .gd files. No Godot engine is invoked.

# Indented text graph
gdoctor graph ./my-godot-game

# Mermaid flowchart (paste into GitHub Markdown or Mermaid Live)
gdoctor graph ./my-godot-game --format mermaid --output graph.md

context — AI-friendly report

gdoctor context <project_path> [--issue "<free text>"] [--output <path>]

Generates a self-contained Markdown document you can paste into ChatGPT, Codex, or another coding agent. The "Suggested Investigation Focus" section uses deterministic keyword rules — no external API calls are made.

gdoctor context ./my-godot-game --issue "game crashes on Android"
gdoctor context ./my-godot-game --issue "missing resource on startup" --output ctx.md

Output formats (scan)

text (default)

ANSI colour-coded terminal output, grouped by severity. Falls back to ASCII icons ([E], [W], [i]) on narrow-encoding terminals (Windows CP949 / GBK).

json

Stable, machine-readable JSON for CI pipelines and AI code agents:

{
  "schema_version": "1.2",
  "project_root": "/path/to/game",
  "summary": { "project_name": "My Game", "main_scene": "res://scenes/Main.tscn" },
  "file_stats": { "scenes": 3, "scripts": 12 },
  "issue_counts": { "ERROR": 1, "WARNING": 2, "INFO": 1 },
  "refs": [
    {
      "source_file": "scenes/Main.tscn",
      "kind": "ext_resource",
      "type": "Script",
      "uid": "uid://abc123",
      "path": "res://player/player.gd",
      "id": "1",
      "resolved_path": null,
      "resolved_via": null
    }
  ],
  "issues": [ { "code": "MISSING_EXT_RESOURCE", "severity": "ERROR" } ]
}

Schema history

Version Added fields
1.0 initial
1.1 refs[].kind
1.2 refs[].resolved_path, refs[].resolved_via

resolved_path is set when path is a uid:// reference that was resolved via a .uid sidecar, .import file, or uid_cache.bin. resolved_via is "uid_sidecar", "import", or "uid_cache" accordingly.

markdown

Simple Markdown report suitable for GitHub issues or documentation.

sarif

SARIF 2.1.0 for GitHub Code Scanning:

gdoctor scan ./my-godot-game --format sarif --output gdoctor.sarif

Use the bundled GitHub Action to scan and upload in one step:

# .github/workflows/godot-doctor.yml
- uses: chamcat97/godot-project-doctor@v0.8.2
  with:
    project-path: .
    fail-on: warning
    upload-sarif: "true"
  permissions:
    security-events: write

Checks

Code Severity Description
CIRCULAR_DEPENDENCY ERROR A cycle exists in the resource dependency graph (e.g. scene A → scene B → scene A)
MISSING_MAIN_SCENE ERROR run/main_scene in project.godot points to a file that does not exist
MISSING_AUTOLOAD ERROR An autoload path in project.godot does not exist
MISSING_EXT_RESOURCE ERROR A .tscn/.tres/.gd file references a path that does not exist
LARGE_TEXTURE WARNING Raster image exceeds 2048×2048 px (requires Pillow)
LARGE_AUDIO WARNING Audio file is larger than 10 MB
DUPLICATE_UID WARNING Two or more sources claim the same uid:// for different files
BROKEN_SIGNAL_CONNECTION WARNING A .tscn signal connection's method is not found in the target node's attached GDScript (inherited methods not checked — false-negatives possible)
UNDEFINED_INPUT_ACTION WARNING GDScript calls Input.is_action_*()/get_action_strength() with a name not declared in project.godot [input] (built-in ui_* actions excluded)
UNUSED_AUTOLOAD WARNING Autoload singleton name not referenced in any .gd file (access via get_node('/root/...') or non-GDScript code are false positives)
UNUSED_ASSET_CANDIDATE WARNING Asset not referenced by any parsed scene, resource, or script
UNUSED_SCRIPT WARNING .gd file not referenced by any scene, resource, autoload, or class_name usage (extends, typed vars, scene node type=, are tracked; dynamically loaded or tool scripts may still be false positives)
NO_MAIN_SCENE INFO run/main_scene is not configured (may be intentional for library projects)
NO_EXPORT_PRESETS INFO export_presets.cfg is absent

uid:// paths: gdoctor resolves uid:// references from three sources — *.uid sidecar files (highest priority), *.import files, and .godot/uid_cache.bin (best-effort binary parse, fails silently). Resolved UIDs are checked for existence and excluded from unused-asset candidates. Unresolvable UIDs are silently skipped to prevent false positives.

Note on UNUSED_ASSET_CANDIDATE: Dynamic load() calls with variable paths cannot be detected by static analysis. Assets loaded that way will still appear as unused candidates.


Development

# Install dev dependencies (includes mypy, ruff, pytest)
pip install -e ".[dev]"

# Run tests
pytest

# Lint
ruff check src tests

# Format
ruff format src tests

# Type-check
mypy src/godot_project_doctor

Roadmap

Completed (v0.2.1 – v0.8.0)

  • ✅ Circular dependency detection
  • ✅ Missing resource detection with uid:// resolution (sidecar, .import, uid_cache.bin)
  • ✅ Config-driven severity overrides and baseline suppression
  • ✅ SARIF 2.1.0 output for GitHub Code Scanning
  • ✅ GitHub Action for CI/CD integration
  • ✅ Input action validation (GDScript Input.* vs project.godot [input])
  • ✅ Signal connection validation (.tscn signal → target GDScript method)
  • ✅ Unused script and autoload detection

Future

  • Binary .res/.scn file support (requires Godot binary format parser)
  • GDScript dynamic path heuristics (partial coverage via string concatenation patterns)
  • Scene node tree analysis (orphaned nodes, mismatched node types)

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

godot_project_doctor-0.8.2.tar.gz (65.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

godot_project_doctor-0.8.2-py3-none-any.whl (47.2 kB view details)

Uploaded Python 3

File details

Details for the file godot_project_doctor-0.8.2.tar.gz.

File metadata

  • Download URL: godot_project_doctor-0.8.2.tar.gz
  • Upload date:
  • Size: 65.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for godot_project_doctor-0.8.2.tar.gz
Algorithm Hash digest
SHA256 05a27d541c6c9822f0687416141abe275b1768acd5ef3a519c087afcb0397df0
MD5 ce484477f88b503570185107d941342a
BLAKE2b-256 4ec5fd71edcaf4c46e48b996bf949e808290c6b633f52de1b1d02f742c71c5b2

See more details on using hashes here.

File details

Details for the file godot_project_doctor-0.8.2-py3-none-any.whl.

File metadata

File hashes

Hashes for godot_project_doctor-0.8.2-py3-none-any.whl
Algorithm Hash digest
SHA256 e5d502c8b399caac2efab9b3278d94db2b27da9490164dae564a868d9160461c
MD5 be9cedd271651862ccb3ed6e81ee77e9
BLAKE2b-256 cb7bf901f6debfe3efde797d5e02d00c68d9bb4614e95c71c1c23c2048947c2f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page