Skip to main content

gd-tools

A modern development workflow CLI for GDScript projects in Godot 4.5+.

CI Coverage PyPI version Python versions Godot version License: MIT


1. Overview

gd-tools brings professional development tooling to GDScript -- test, lint, format, and code coverage in a single CLI. It wraps gdtoolkit for linting and formatting, runs its own Godot-native test runtime, and fills the remaining gap with a custom hybrid coverage system -- production-quality line and branch coverage for GDScript that no existing tool provides.

Tests are written against GdToolsTest, a native GDScript base class that runs inside your Godot project, so a test can touch the real scene tree, await real signals, and assert on real engine objects without leaving the engine. Existing suites that extend GutTest run through the built-in compatibility bridge -- no GUT addon required -- while projects migrate. The bridge is deprecated as of v0.5.0 and will be removed in v0.6.0.

One install, one config, one mental model.

2. Features

Feature Description
Unified workflow One install, one config (gd-tools.toml), one mental model for test, lint, format, and coverage. Consistent terminal output with colored markers and summary footers across all commands.
Native test runtime Tests extend GdToolsTest and run inside Godot itself. Scene and resource integration tests reach the real scene tree through an explicit context object rather than a proxy.
Zero-friction bootstrap gd-tools init gets a project fully set up in under a minute -- native test and coverage addons deployed, configs generated. Existing GutTest suites run through the built-in compatibility bridge with no addon install.
Coverage gap-filling Production-quality line and branch coverage for GDScript -- HTML, LCOV, and Cobertura reports that integrate with CI and code review tools. # gd-tools: no cover annotations exclude debug-only code from the numbers.
CI/CD friendly Exit codes, --check flags, machine-readable output (JSON, JUnit XML, LCOV, Cobertura), no interactive prompts in CI mode.
Standalone compatibility gdlint and gdformat continue to work if invoked directly. gd-tools is a layer on top, not a lock-in.

3. Installation

pip install gd-tools-cli

gd-tools requires Python 3.10+ and a Godot 4.5+ binary on your system. The Godot binary is auto-detected from configuration, environment variables (GODOT_BIN, GODOT4_BIN, GODOT_PATH), PATH, or common install locations.

4. Quick Start

# 1. Install
pip install gd-tools-cli

# 2. Bootstrap your Godot project
cd your-godot-project
gd-tools init

# 3. Run your tests
gd-tools test

# 4. Run tests with coverage
gd-tools test --coverage --min 80

# 5. Show uncovered lines and branches when coverage is below 100%
gd-tools test --coverage --show-uncovered

# 6. Force plan regeneration, bypassing the coverage plan cache
gd-tools test --coverage --no-cache

gd-tools init deploys the native test addon and the coverage addon, generates gd-tools.toml, gdlintrc, and gdformatrc, and creates the .gd-tools/ directory. The command is idempotent -- safe to re-run. If you've modified coverage addon files, they are automatically backed up to addons/gd-tools-coverage/.backups/ before being overwritten.

The legacy GUT runtime has been replaced by the built-in compatibility bridge: suites extending GutTest run on the native runtime with no GUT addon installed. The bridge is deprecated as of v0.5.0 and will be removed in v0.6.0. See the migration guide for the supported subset and the steps to move fully onto GdToolsTest.

A test suite is any class extending GdToolsTest:

extends GdToolsTest

func test_health_starts_at_full() -> void:
    assert_eq(health.current(), 100)

5. CLI Command Summary

Command Description
gd-tools init Bootstrap a Godot project -- deploy the native test and coverage addons, generate configs.
gd-tools doctor Diagnose the development environment -- Godot, native test addon, bridge-eligible GUT suites, coverage addon, tooling.
gd-tools test Run tests with optional coverage, thresholds, and JUnit XML output. Suites extending GdToolsTest and GutTest are detected and routed automatically (GutTest suites run through the compatibility bridge). Accepts optional path arguments to override configured test directories. --watch re-runs affected suites on .gd file changes. Every run publishes a machine-readable artifact index under .gd-tools/artifacts/<run_id>/.
gd-tools migrate Guided GUT-to-native migration. Default: read-only report with unsupported-construct inventory and proposed base-class rewrites. --apply renames clean suites to GdToolsTest and translates .gutconfig.json into gd-tools.toml (merge, never clobber). --config-only translates config only.
gd-tools lint Lint GDScript files using gdlint with text or JSON output. Accepts one or more file or directory paths.
gd-tools format Format GDScript files using gdformat with check and diff modes. Accepts one or more file or directory paths.
gd-tools coverage Coverage subcommands -- report, merge, show, save-baseline, and diff (baseline comparison for CI regression gates).
gd-tools config Configuration management -- show (display resolved config), validate (check config validity).
gd-tools version Display versions of all gd-tools components (gd-tools, Godot, gdtoolkit, Python, and GUT when installed) in a table or JSON.
gd-tools completion Generate shell completion scripts for bash, zsh, fish, or PowerShell.

Selecting and Filtering Tests

gd-tools test                              # every discovered suite
gd-tools test --suite PlayerTests          # one suite, by class name
gd-tools test --test test_takes_damage     # one test method
gd-tools test --tag smoke                  # suites with that class-level tag
gd-tools test --test-timeout 30            # per-test timeout, in seconds

--tag is repeatable, and --test-timeout (per test) is separate from --timeout (per suite process).

Each run writes a machine-readable artifact index under .gd-tools/artifacts/<run_id>/, listing the manifest, result, event stream, engine log, coverage data, and any failure screenshots the run actually produced. Only the latest run is retained. See the User Guide for the full artifact tree.

Watch Mode

gd-tools test --watch                      # watch .gd files, re-run on change
gd-tools test --watch --coverage           # every re-run includes coverage
gd-tools test --watch --tag smoke          # filters apply to every run

--watch runs the full suite once, then keeps watching: saving a .gd file re-runs the tests affected by the change. The changed file is mapped to its suite by convention — src/enemy.gd re-runs tests/test_enemy.gd or tests/enemy_test.gd — with a full-suite fallback (announced explicitly) when no suite matches. Rapid successive saves are coalesced into a single re-run, and a save during a running suite queues exactly one follow-up run.

  • Native runtime only: the removed legacy GUT runtime (--runtime gut) is rejected with exit 2; GutTest suites run through the compatibility bridge.
  • Interactive only: --watch combined with CI=true exits 2.
  • The terminal is cleared between runs; the banner shows how many files are watched, and Ctrl+C always exits 0.
  • Positional path arguments are not supported with --watch; the watched scope is the project root minus standard excludes (.godot/, .gd-tools/, .git/, and the gd-tools addons).

Native Runtime vs. GUT Compatibility Bridge

The native runtime is the default and the forward path. Suites extending GutTest run through the built-in compatibility bridge on the same native runner; the bridge is deprecated as of v0.5.0 and will be removed in v0.6.0.

Capability Native runtime (GdToolsTest) Bridge (GutTest)
Base class GdToolsTest extends Node GutTest, provided by gd-tools (no GUT addon)
Discovery test_* methods, by directory or exact file selector Same; routed automatically per file
Lifecycle hooks before_all, after_all, before_each, after_each Same, plus prerun_setup and postrun_teardown
Assertions Full native assertion set plus fail(), skip_test(), pending_test() Documented GUT core subset -- unsupported constructs fail at preflight
Async waits wait_process_frame, wait_physics_frames, wait_seconds, wait_for_signal(signal, timeout) GUT helper family, incl. wait_until, wait_while, yield_*
Tags Class-level tags, filtered with --tag Same
Test selectors --suite, --test, --test-timeout Same
Scene and resource integration const INTEGRATION plus GdToolsTestContext for scene root, node lookup, named resources, and bounded signal waits Not wired into the bridge shim
Retries Configurable per test ([test].retries) Same
Line and branch coverage Yes Yes
JUnit XML output Yes Yes
Mocking and stubbing double(), partial_double(), stub() (.to_return/.to_call_super), assert_called* family Same -- inherited from GdToolsTest with identical semantics
Parameterized tests parameterize() in before_all, values injected via use_parameters Not supported -- preflight rejects parameterize()
Skipping a test at runtime skip_test() and pending_test() Yes
Parallel execution Not yet -- suites run sequentially Same
Editor plugin Not yet Not applicable

Known limitations. Parameterized tests are native-only -- the bridge deliberately refuses parameterize() at preflight rather than mis-running them, so such suites must migrate to GdToolsTest. Suites run sequentially; parallel execution is planned but not yet available. The bridge itself is deprecated as of v0.5.0 and will be removed in v0.6.0. See the migration guide for the bridge's supported subset, User Guide for the full flag reference, and Roadmap for what is planned.

Verbosity Control

gd-tools supports two global flags that control output verbosity. Place them before the subcommand:

Flag Short Description
--verbose -v Show underlying commands and timing information.
--quiet -q Suppress non-essential output (update checks, info messages, detailed tables).

The flags are mutually exclusive -- using both exits with code 2.

# Verbose: see the Godot command and elapsed time
gd-tools --verbose test

# Quiet: minimal output for CI pipelines
gd-tools --quiet lint
gd-tools --quiet doctor

# Default: current behavior (no change)
gd-tools test

Always shown (regardless of flag): test pass/fail summaries, lint violations, coverage reports, error messages, and exit codes.

See the User Guide for full command reference, flags, examples, and exit codes.

6. Shell Completion

gd-tools supports tab completion for bash, zsh, fish, and PowerShell. Generate a completion script with gd-tools completion <shell> and source it in your shell configuration.

Bash:

# Add to ~/.bashrc or ~/.bash_profile
eval "$(gd-tools completion bash)"

Zsh:

# Add to ~/.zshrc
eval "$(gd-tools completion zsh)"
# Or save to a file in your fpath:
gd-tools completion zsh > ~/.zsh/completions/_gd-tools

Fish:

gd-tools completion fish > ~/.config/fish/completions/gd-tools.fish

PowerShell:

gd-tools completion powershell | Out-String | Add-Content $PROFILE

Alternative -- Click's environment variable:

Click also supports completion via the _GD_TOOLS_COMPLETE environment variable. This is useful for advanced users who prefer not to modify their shell profile:

# Bash example
export _GD_TOOLS_COMPLETE=bash_source
eval "$(gd-tools)"

See the User Guide for detailed per-shell instructions.

7. Configuration

gd-tools uses a single gd-tools.toml file as the source of truth for all tool configuration. gd-tools init generates this file with sensible defaults.

[godot]
binary = ""  # Optional -- auto-detected if unset

[test]
test_dirs = ["test", "tests"]
prefix = "test_"
suffix = ".gd"
gutconfig = ".gutconfig.json"  # legacy; not read by the native runtime or the bridge
runtime = "native"        # native (default); "gut" is no longer a runnable runtime
timeout_seconds = 5.0     # default per-test timeout for async native tests
retries = 0               # opt-in retries per native test
tags = []                 # native suite tag filters

[lint]
exclude = ["addons", ".godot", ".gd-tools", ".git"]

[format]
exclude = ["addons", ".godot", ".gd-tools", ".git"]

[coverage]
enabled = false
min_percent = 0
format = "html"  # html, lcov, cobertura, text
output_dir = ".gd-tools/coverage"
exclude = ["addons", ".godot", ".gd-tools", ".git"]
test_dirs = ["test", "tests"]

See the User Guide for a full configuration reference with all keys, defaults, and examples.

8. Documentation

Document Description
User Guide Complete CLI reference -- all commands, flags, examples, and troubleshooting.
Contributing Guide Development setup, code style, testing requirements, and PR process.
Architecture System architecture -- hybrid coverage instrumentation and the native test runtime.
Product Requirements Full product specification -- features, design decisions, technical detail.
Roadmap Release phases and milestones.
Testing Strategy Test pyramid, coverage targets, and CI integration.

9. Development

# Clone and install in editable mode with dev dependencies
git clone https://github.com/mansyar/gd-tools.git
cd gd-tools
pip install -e ".[dev]"

Running Tests

Unit tests run without Godot. Integration tests require a Godot 4.5+ binary -- configure via .env (see .env.example):

cp .env.example .env
# Edit .env: set GODOT_BIN to your Godot binary path

# Run all tests with coverage
CI=true pytest

CI=true is what makes a missing Godot binary a failure rather than a skip. Without it, integration and end-to-end tests skip quietly when Godot is absent, so a run can report success having executed nothing.

See Testing Strategy for the full testing guide and Contributing Guide for development setup details.

10. License

MIT

11. Acknowledgements

gd-tools stands on the shoulders of two excellent community tools. It wraps them; it does not replace them. Full credit to their authors for the hard parts.

  • GUT (Godot Unit Test) by bitwes: the GDScript test framework whose core API the built-in compatibility bridge reproduces while projects migrate to the native runtime.
  • gdtoolkit by Scony: provides gdlint and gdformat, which gd-tools lint and gd-tools format wrap.

The native test runtime (GdToolsTest) and the custom hybrid coverage system (plan generation, runtime instrumentation, and reporting) are the original work of gd-tools and fill the gaps these tools do not cover.

Metadata

Release files for gd-tools-cli 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gd-tools-cli 0.5.0
File Size Uploaded
gd_tools_cli-0.5.0.tar.gz 156.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for gd-tools-cli 0.5.0
File Interpreter ABI Platform
gd_tools_cli-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 336.3 kB

Release files / gd_tools_cli-0.5.0.tar.gz

Download URL gd_tools_cli-0.5.0.tar.gz
Size 156.4 kB
Tags Source
SHA-256 checksum
How to use checksums
c8dfe50a5e5ffea1b4b9422af5a9fcf5b4529378b1fa4a318e73581bdf43860d
BLAKE2b-256 checksum
How to use checksums
782775013cf29e91e11b9ab6fa97254e3703e8ac6a26b00e95426d00fd012309
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release files / gd_tools_cli-0.5.0-py3-none-any.whl

Download URL gd_tools_cli-0.5.0-py3-none-any.whl
Size 179.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d5e302df33fb98caaa6ece68244b731448211a73fa7829f4bc5944a1b98ab035
BLAKE2b-256 checksum
How to use checksums
d57d7e4a9fc29a042559e04e680296f4c2999398f9efdfb737f8e949e4331fc8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release history Release notifications | RSS feed

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

This release

0.5.0 This release

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page