Contributing
Prerequisites
- Rust >= 1.85 (tested with 1.96)
- Godot 4.4+ (tested with 4.7) with GDExtension support
- Linux (primary target), macOS (untested) or Windows 11 (untested).
Setup
Clone the repository
# Clone
git clone https://github.com/godot-pty/gpty.git gpty
cd gptyInstall git hooks (one-time per clone)
./scripts/install-hooksThis installs:
pre-commit(fast checks:fmt,lint,clippy)commit-msg(Conventional Commits enforcement)pre-push(full CI suite).
Run ./scripts/ci-check directly to validate changes before committing.
Build
Editor / day-to-day (res://bin/*.so should symlink to target/debug/):
ln -sfn ../../target/debug/libgpty_gdext.so godot/bin/libgpty_gdext.linux.x86_64.so
cargo build -p gpty-gdext && cd godot && godot -eRestart the editor after a rebuild so it remaps the .so.
One-shot standalone build (detects the host platform, builds gpty-gdext in release mode, stages it into godot/bin/, and exports into dist/):
./scripts/buildRequires Godot on PATH with export templates installed for its version. The manual steps below are what the script does internally.
# Build the GDExtension library (required before running Godot)
cargo build -p gpty-gdext
# Release build + stage into godot/bin for export
cargo build -p gpty-gdext --release
cp target/release/libgpty_gdext.so godot/bin/libgpty_gdext.linux.x86_64.so
godot --headless --path godot --import
godot --headless --path godot --export-release "Linux/X11" ../dist/gptyClean
Remove build/test artifacts for a clean slate — stale IPC sockets, Godot import caches, and standalone dist/ outputs:
./scripts/clean # default: transient artifacts
./scripts/clean --dry-run # list what would be removed
./scripts/clean --all # also remove target/ and built gdext librariesSockets with a live listener (a running GUI or an in-flight test run) are never touched, and user data (user:// settings, profiles, layouts, history.db) is preserved. Tracked files such as dist/aur/ and godot/.gutconfig.json are left alone.
MCP
Generate the current tools manifest: cargo run --bin gpty -- schema --format mcp
Run
# Open in Godot editor
cd godot && godot -e
# Launch the GUI (backgrounded; add --headless for headless)
godot --path godot &The GUI starts an IPC server on $XDG_RUNTIME_DIR/gpty.sock (or GPTY_SOCKET env var if set).
Once running, control it with the CLI:
cargo run --bin gpty -- version
cargo run --bin gpty -- new-pane -t terminal
cargo run --bin gpty -- list-panes
cargo run --bin gpty -- inject T1 -t "echo hello"
cargo run --bin gpty -- daemon stopStandalone commands (no GUI needed):
cargo run --bin gpty -- schema # JSON Schema
cargo run --bin gpty -- schema --format mcp # MCP tools manifest
echo '{"jsonrpc":"2.0","id":1,"method":"initialize"}' | cargo run --bin gpty -- mcpTest
- Automated:
./scripts/ci-checkruns the full suite (Rust + GUT + audit). CI runs on every push tomainand every PR. - Manual pre-release: docs/content/docs/testing.md — smoke tests for CLI bridge, daemon lifecycle, UI shortcuts, and error paths that require a running GUI.
- Test format:
Given / When / Thenwith expected output. See the manual checklist for examples.
# Rust tests only
cargo test --workspace # Tests across core, gdext, cli
cargo test -p gpty-core # Core library only
# Rust type-check (fast, no codegen)
cargo check
# Godot (GUT) tests only
godot --headless --path godot --import # Required before first run
godot --headless --path godot -s addons/gut/gut_cmdln.gd -d -gdir=res://tests/unit -gdir=res://tests/integration
# OMP extension unit tests (no omp install required)
(cd extensions/gpty-omp-events && node --test)
# Explicitly link the OMP observability plugin (user action; gpty never auto-installs)
omp plugin link "$(pwd)/extensions/gpty-omp-events"
# Run all CI checks locally (fmt, clippy, tests, GUT, audit)
./scripts/ci-check
# Fast checks only (fmt, clippy)
./scripts/ci-check --fast
# Terminal renderer cost (needs a display; see the script header)
godot --path godot --disable-vsync -s res://tests/bench/draw_bench.gdThe render benchmark fills a pane with a deterministic ANSI-rich screen, prints
the cost of a forced full repaint against an idle frame, and saves the rendered
frame to /tmp/gpty_draw_<BENCH_TAG>.png. Two revisions must render
byte-identical pixels, so diff the two PNGs before trusting a timing delta.
CLI (control a running GUI)
cargo run --bin gpty -- new-pane --pane-type terminal # Create a new terminal pane
cargo run --bin gpty -- new-pane --pane-type inspector # Private Inspector Q&A pane
cargo run --bin gpty -- new-pane --pane-type reasoning # Passive Reasoning pane
cargo run --bin gpty -- list-panes # List active panes
cargo run --bin gpty -- schema # JSON Schema for AI tools
cargo run --bin gpty -- schema --format mcp # MCP tools manifestVerbose logging: RUST_LOG=debug cargo run --bin gpty -- version
Project Structure
See AGENTS.md for the full directory tree.
Code Style
See AGENTS.md for the complete GDScript and Rust conventions, pitfalls, and patterns.
Pull Request Process
- Fork the repository.
- Create your feature branch.
- Make your changes.
- Test your changes (functionally).
- Run
./scripts/ci-check— ensure all checks pass - Add or update test cases as applicable.
- See AGENTS.md for commit information.
- Submit a pull request.
Security
See AGENTS.md for full security rules, including Concept Engine ReDoS prevention and OSC 52 clipboard restrictions.
License
gPTY is licensed under the GNU General Public License, version 3 or later - see License. License exceptions adds section 7 permissions so plugins, extensions, adapters, and data files can stay permissive (Apache-2.0, MIT, or their authors’ own terms).
There is no CLA. By opening a pull request you confirm that you wrote the contribution (or otherwise have the right to submit it) and you license it to the project under those same terms: GPL-3.0-or-later, plus the exceptions in LICENSE-EXCEPTIONS.md.