Skip to content

Releases: kurushimee/gdls

v1.0.7 — utility-as-Callable follow-ups

Choose a tag to compare

@kurushimee kurushimee released this 13 Jun 08:38

Follow-ups to the v1.0.6 utility-as-Callable hotfix (#92), cut from v1.0.6 plus these fixes only — the unreleased Phase 2 work on main stays unreleased.

Fixed

  • Bare Variant utilities resolve to a constant Callable under any native-API state, including an empty database (#92). The v1.0.6 arm gated Variant utilities on the ingested extension_api.json table, so when no dump was available (embedded fallback disabled, or a decompress failure) bare print / floor still fell through to Identifier "X" not declared in the current scope.. Resolution now mirrors Godot's compile-time Variant::has_utility_function through a database-independent registry of the 114 Variant utilities, so the fix holds regardless of how — or whether — the native API was loaded.
  • Duplicate same-utility dictionary keys are now reported (#92): {print: 1, print: 2} emits Godot's Key "@GlobalScope::print" was already used in this dictionary (at line N). (and @GDScript::len for the GDScript-only family), matching the engine; previously the duplicate folded to an opaque value and went unreported. Distinct keys and non-utility constants are unaffected.

Changed

  • The constant-Callable type is now built by a single make_callable_type helper mirroring Godot's gdscript_analyzer.cpp, replacing eight inline copies (#92) — groundwork for the Phase 2 signatureHelp MethodInfo wiring. No behavior change.

Both conformance ratchets hold at 1.0, a new ingest guard pins the full 114-name Variant utility set, and the duplicate-key messages are oracle-verified against godot 4.6.3-stable. The full-project diagnostics sweep on both acceptance projects (a public OSS project and a ~2,300-script production project) is byte-identical to v1.0.6.

Install

Download the binary for your platform, verify it against SHA256SUMS, and point your editor's GDScript LSP at it. Both binaries report gdls 1.0.7.

v1.0.6 — utility functions as first-class Callables

Choose a tag to compare

@kurushimee kurushimee released this 13 Jun 01:42

Hotfix for a false-positive analyzer error reported from real-project use (#88). Cut from v1.0.5 plus this fix only — unreleased Phase 2 work on main is not included.

Fixed

  • Bare utility-function references no longer error with Identifier "X" not declared in the current scope. (#88). Godot 4.x exposes utility functions as first-class Callables, so print.call_deferred(msg), arr.map(floor), var f := absi, and clamp.bind(0, 1) are all legal — the reduce_identifier arm that resolves them (gdscript_analyzer.cpp:4641-4652) was unported, and every Variant utility referenced outside callee position false-positived. Bare references to both utility families (Variant + GDScript-only) now reduce to a constant Callable, matching Godot's make_callable_type shape.
  • GDScript-only utilities (len, range, …) referenced bare previously escaped the error but carried no type; they now get the same constant Callable, fixing hover and := inference on those forms.
  • const PRINTER = print is accepted (the reference folds as a constant, mirroring Godot's reduced_value = Callable(...)), and print = 5 now fails with Godot's exact Cannot assign a new value to a constant. instead of the bogus not-declared error.

Fidelity

  • Every regression-test expectation is oracle-pinned against godot 4.6.3-stable --headless --check-only; the differential-oracle harness gains a utility-as-Callable fixture (19/19 fixtures at jaccard 1.0).
  • Both conformance ratchets hold at 1.0 with empty known-failures lists.
  • Diagnostics sweeps on both acceptance projects (a ~240-script OSS project and a ~2,300-script production project) compare clean against v1.0.5: error baselines hold, with the production project's #88-class false positives resolved.

Install

Download the binary for your platform, unpack, and point your editor's LSP client at it (stdio). Verify with gdls --versiongdls 1.0.6; checksums in SHA256SUMS.

v1.0.5 — LSP protocol conventions

Choose a tag to compare

@kurushimee kurushimee released this 12 Jun 11:42
cafc1d9

The LSP protocol-conventions release. A post-v1.0.4 audit compared every exposed capability against the LSP 3.17 spec and the rust-analyzer/gopls/clangd conventions and filed twelve issues (#43#54); this release closes all of them. Godot message strings, spans, and severities are untouched throughout: both conformance ratchets hold at parser 186/186 and analyzer 300/300.

Ranges anchor the symbol name token (#44, #46, #48)

  • Cross-file definition returns the member's name token, not the whole declaration node — MemberDecl records name_span at interface-extraction time (index cache format v4; old caches rebuild cold once on upgrade). Native-stub jumps land on the member's name token too.
  • workspace/symbol results carry real name-token ranges instead of zero-width points at column 0.
  • callHierarchy fromRanges cover the callee name token instead of the whole call expression — multi-line calls no longer highlight entire blocks.

Client capabilities honored (#43, #45, #47, #52)

  • documentSymbol downgrades to flat SymbolInformation[] for clients without hierarchicalDocumentSymbolSupport (Helix explicitly declines the nested shape).
  • references honors includeDeclaration: false as a filter at final assembly.
  • The empty workspace/symbol query returns all symbols (classes first, capped at 256) so symbol pickers open populated.
  • UNUSED_/UNREACHABLE_ diagnostics carry DiagnosticTag.Unnecessary (editors fade dead code), gated on client tagSupport; every warning-coded diagnostic links Godot's warning docs via codeDescription.

Call hierarchy correctness (#49, #50, #51)

  • Outgoing to items are expandable (they carry the same data blob prepare/incoming items do; data-less items re-resolve from uri + selectionRange).
  • Native callees anchor into their API stubs at the member's name token — the fabricated (0,0)-in-the-caller's-file item is gone, and unresolvable callees are omitted.
  • detail is populated everywhere: documentSymbol outlines render member signatures, call-hierarchy items carry their res:// script path (native items the declaring class).

Navigable diagnostics (#53)

  • SHADOWED_VARIABLE / SHADOWED_VARIABLE_BASE_CLASS publish relatedInformation pointing at the shadowed declaration's name token, even cross-file. Message strings stay byte-identical.

References precision (#54, pulled forward from Phase 2)

  • Binding::Call classifies its callee as a CalleeTarget (Script with owning class path / Native / Unresolved) derived from the resolution the dispatch actually used.
  • In-file attribute reads (self.hp) record Binding::Use, closing the last attribute-read recording gap.
  • References on resolved member targets are binding-backed: unrelated same-named members in different classes no longer report each other's sites; the "over-approximate, never under-report" raw scan survives only where resolution genuinely can't decide.

Validation

  • Diagnostics sweeps held exactly on both acceptance projects: Pixelorama (0 error-files / 119 warnings, strict profile identical) and a 2,338-script production project (error and warning baselines identical to v1.0.4).
  • Three-layer fuzz gate (parse + analyze + index_invariants) clean; differential oracle vs Godot 4.6.3-stable green.

Install

Download the binary for your platform, unpack, and point your editor's LSP client at gdls (stdio). Verify with sha256sum -c SHA256SUMS.

Known issues — fixed in v1.0.6

  • Bare utility-function references (print.call_deferred(msg), arr.map(floor), var f := absi, const PRINTER = print) false-positive Identifier "X" not declared in the current scope. (#88) — fixed in v1.0.6.

v1.0.4 — native-surface completeness

Choose a tag to compare

@kurushimee kurushimee released this 11 Jun 20:49
83a651e

The native-surface completeness release. v1.0.3's real-project capability walks (a 243-script
OSS project and a 2,338-script production project) showed script-side navigation had outpaced
the native side: hover on a native member fell back to a degraded type label, definition on a
native class or member had nowhere to jump, workspace/symbol anchored every global class at
line 0, and the analyzer dropped to dynamic exactly where upstream's class-resolution loop
falls through to the native check — the same gap that kept UNSAFE_PROPERTY_ACCESS deferred.
Every v1.0.4 issue clustered on that surface (#32#35); the adjacent gaps the work surfaced
were fixed in the same pass (#37#41).

Added — native hover (#35, #40)

  • Native member and class hover render real declaration lines via a shared native_render
    formatter pinned to Godot's gdscript_workspace.cpp detail formats, with native + builtin
    arms in both member paths (call callees and plain attribute access). Bare calls resolve
    implicit self through the extends chain, and @GlobalScope utility functions render too
    (#40). Class-name hover upgrades to <Native> class X extends Y.

Added — definition into native API stubs (#34, #38, #39)

  • definition on a native class or member materializes a readable API stub under the
    user-level cache (stubs/v{N}-{hash}/Class.gd; per-request keying, atomic write-if-absent)
    and returns a plain file:// Location into it: the class header for class references, the
    declaring class's member line for members — implicit-self member calls included (#38). The
    native arms run only after every project resolution has missed, stub buffers publish empty
    diagnostics, the stub tree is GC'd once per session (#39), and a stubCacheDir seam keeps it
    testable.

Added — analyzer native fall-through + UNSAFE_PROPERTY_ACCESS (#32, #37)

  • The CLASS-branch native tail restores upstream's class-loop → native-check fall-through,
    type_from_type_ref gains its enum/bitfield arms (gdscript_analyzer.cpp:5744-5759), and
    reduce_call probes the native surface on an interface miss (#37) — so int-typed native
    surfaces resolve faithfully instead of silently degrading to dynamic.
  • UNSAFE_PROPERTY_ACCESS now fires (gdscript_analyzer.cpp:4880-4886) — until now the one
    deliberately-deferred warning code. Emission stays gated on negative-claim soundness:
    unresolvable chain roots and cross-file shallow-interface misses are silent under any
    provenance, so the warning can't lie. Conformance holds 300/300 with the warning live. On
    the OSS acceptance project the default profile holds 0 errors while the strict profile gains
    +677 genuinely subtype-dependent UNSAFE_PROPERTY_ACCESS findings — and sheds 50
    UNSAFE_CALL_ARGUMENT + 29 UNSAFE_CAST false positives from the same typing improvements.

Fixed — workspace/symbol anchors (#33)

  • ClassEntry records the class_name declaration line + identifier span at index time
    (cache format v3): workspace/symbol anchors global classes at their declaration instead of
    a zero-width line-0 location, and the closed-file definition path drops its per-lookup
    re-parse.

Changed

  • gd_types groundwork: NativeDb::lookup_member/lookup_builtin_member chain-walk the
    class hierarchy and report the declaring class, Param.default_value survives ingestion, and
    display_type produces the hover labels.
  • scan_diags.py grows --strict and a per-code warning histogram, so the release-gate
    sweep can gate the strict profile too. Error baselines hold exactly on both acceptance
    projects, verified per-platform.

Fixed — hardening

  • Stub machinery: per-session render cache, rename-race fallback, sentinel-mtime GC
    freshness, a stub-name guard, span content checks, and a native chain-walk depth cap.
  • The analyze fuzz target is revived and wired into CI's bounded fuzz job (#41) — it had
    rotted out of the build (95,904 clean runs / 121 s locally).

Install

Download the binary for your platform, unpack it, and point your editor's LSP client at gdls
over stdio (no Godot process needed at runtime):

  • Linux x86_64: gdls-v1.0.4-linux-x86_64.tar.gz
  • Windows x86_64: gdls-v1.0.4-windows-x86_64.zip

Verify downloads with sha256sum -c SHA256SUMS.


Known issues — fixed in v1.0.5: LSP protocol-convention gaps (#43#54) — declaration-node/zero-width ranges, ignored client capabilities (hierarchicalDocumentSymbolSupport, includeDeclaration, empty workspace/symbol query, diagnostic tags), dead-end / fabricated call-hierarchy items, missing detail metadata, and references over-reporting.

v1.0.3 — warning emission completeness

Choose a tag to compare

@kurushimee kurushimee released this 11 Jun 01:43
508d0a4

The warning-completeness release. The v1.0.2 plugin sessions exposed that the existing LSP test
suite cannot be the single source of truth: 22+ declared warning codes had no emission site
(#29), @warning_ignore missed multi-line targets (#28), and several navigation capabilities
quietly returned nothing on shapes every real project uses. Each fix was verified the same way
the bugs were found — driving every exposed capability against the two acceptance projects (a
243-script OSS project and a 2,338-script production project) and reading what actually comes
back.

Fixed — analyzer warnings (#28, #29)

  • @warning_ignore covers multi-line targets: the ignored-lines table now records Godot's
    annotation→target-header span per target kind (multi-line signatures, initializers,
    for/if/while/match headers, match-branch patterns) instead of a single line, exactly
    as upstream — body lines past the header still warn.
  • 19 missing warning emission sites ported function-for-function from
    gdscript_analyzer.cpp/gdscript_parser.cpp @ 4.6.3-stable: EMPTY_FILE,
    STANDALONE_EXPRESSION, STANDALONE_TERNARY, UNREACHABLE_CODE, UNREACHABLE_PATTERN,
    ASSERT_ALWAYS_TRUE, ASSERT_ALWAYS_FALSE, INTEGER_DIVISION, INCOMPATIBLE_TERNARY,
    UNTYPED_DECLARATION, INFERRED_DECLARATION, REDUNDANT_STATIC_UNLOAD,
    UNASSIGNED_VARIABLE, UNASSIGNED_VARIABLE_OP_ASSIGN, UNUSED_VARIABLE,
    UNUSED_LOCAL_CONSTANT, RETURN_VALUE_DISCARDED, STATIC_CALLED_ON_INSTANCE,
    INT_AS_ENUM_WITHOUT_CAST. Per-code unit tests in gd_analyze/tests/warning_emissions.rs;
    the conformance ratchet holds 300/300. (DEPRECATED_KEYWORD and the 3 deprecated codes have
    no emission site upstream either and stay silent by fidelity; UNSAFE_PROPERTY_ACCESS stays
    deferred deliberately — the attribute lookup cannot yet make that negative claim truthfully.)
  • Warning output order matches apply_pending_warnings: warnings stable-sort by anchor
    line among themselves; errors keep emission order.
  • Untyped rest parameters no longer error: func f(...args): is an inferred Array plus
    UNTYPED_DECLARATION, not a false-positive type error.

Fixed — navigation (found by the real-project capability walk)

  • definition on a dotted method call through a typed var (cel.on_remove()) now jumps to
    the member declaration in the declaring file.
  • callHierarchy/incomingCalls was structurally empty across files: it now uses the same
    project-wide two-phase textual scan as references (Godot's workspace.cpp:472 strategy)
    instead of the interface-level reverse index, which never contains body-only method names.
  • prepareCallHierarchy on a call-site callee prepares the callee (dotted and bare);
    declaration clicks keep the enclosing-function behavior.
  • <Script #N> no longer leaks into cast errors — the script's class_name (or file
    basename) renders instead, matching Godot's DataType::to_string().

Fixed — logging & CI

  • Bridged log::* events render with their real target/file/line (tracing-log feature), so
    GDLS_LOG per-target directives match them.
  • Bounded 500 ms ETXTBSY retry on the auto-dump Godot spawn (transient "Text file busy").
  • Integration tests read responses by skipping interleaved notifications, like a real client.

Changed

  • Background dump timeout raised 60 s → 5 min (the deadline only reaps a wedged Godot child;
    60 s could kill legitimate slow first boots).
  • No background auto-dump when extensionApiPath is pinned (it was pure waste).
  • Acceptance warning baselines re-based for the new emission sites; error baselines hold
    exactly on both acceptance projects, verified per-platform.

Performance

  • The analyzer's unused-variable/parameter/signal sweeps share one per-analysis decl-identifier
    set instead of rebuilding it per declaration (was O(N × tree size) per function with N
    locals).

Install

Download the binary for your platform, unpack it, and point your editor's LSP client at gdls
over stdio (no Godot process needed at runtime):

  • Linux x86_64: gdls-v1.0.3-linux-x86_64.tar.gz
  • Windows x86_64: gdls-v1.0.3-windows-x86_64.zip

Verify downloads with sha256sum -c SHA256SUMS.


Known issues — fixed in v1.0.4:
hover and definition on native classes and members returned degraded labels or nothing
(#34, #35), workspace/symbol anchored every global class at a zero-width line-0 location
(#33), and the analyzer dropped native typing exactly where upstream's class-resolution loop
falls through to the native check — the gap that also kept UNSAFE_PROPERTY_ACCESS deferred
(#32).

v1.0.2 — first-run robustness: native API fallback chain, background auto-dump, hover declaration signatures

Choose a tag to compare

@kurushimee kurushimee released this 10 Jun 17:20

The first-run robustness release. The first real-world Claude Code plugin session on a fresh
Windows machine hit three failures at once: the synchronous extension_api.json auto-dump
wedged for its full 60 s timeout before the first request was answered, the timed-out dump left
the whole session on an empty native DB — so every native annotation in every file errored
Could not find type "X" in the current scope. — and hover on declarations rendered the opaque
<Script #N> placeholder. v1.0.2 makes the first run converge to the same behavior as every
later run, with no false positives at any point in between. (#24, #25, #26)

Native API resolution (#24)

  • Embedded stock fallback: a gzipped stock 4.6.3 no-docs extension_api.json (0.4 MB) ships
    inside the binary as the last resolution step — builtins (Node, Timer, …) always resolve
    on a fresh install with no Godot anywhere. Kill switch: embeddedApiFallback (default true);
    also covers an unreadable explicit extensionApiPath.
  • Provenance-gated negative claims: the native DB now carries a provenance
    (Exact project-derived / Generic embedded / Absent empty). Native-rooted negative
    diagnostics — the terminal Could not find type, super-call misses, meta-base
    Cannot find member — fire only under Exact: a generic surface can prove what exists,
    never what doesn't (a custom engine build's class is indistinguishable from a typo).
    Documented as a deliberate deviation in docs/02 §11b.

Auto-dump lifecycle (#25)

  • The dump runs on a background thread and is adopted mid-session (reload native DB →
    republish open buffers → refresh the warm-start cache). The first request never queues behind
    a Godot boot; first-run diagnostics converge the moment the dump lands.
  • Child stdout/stderr are drained concurrently — a chatty engine boot could fill the 64 KB pipe
    and ride the whole dump into the timeout.
  • "The artifact decides" now covers the timeout path: a deadline-killed Godot that already wrote
    a complete dump is adopted (parse-validated; torn files quarantine and fall through).
  • Mid-session reload stability: a reload resolving strictly worse than the live DB (torn read of
    a mid-write dump) keeps the live DB; identical content (the post-adoption watcher echo) skips
    the re-analyze. Edits also refresh open dependents' diagnostics immediately.

Hover (#26)

  • Declaration-site signatures: hover on the name of a func/var/const/signal/inner
    class renders the member's signature through the same formatter as the call-site hover
    (statics show static in both). Inner-class members resolve through their interface scope.
  • Human type labels: script-typed values render their class_name (or file basename) —
    the <Script #N>/<Class> placeholders never reach hover output. Untyped members with an
    inferred initializer append the resolved type.

Validation

Conformance ratchets hold at parser 186/186 + analyzer 300/300; differential oracle vs
stock Godot 4.6.3 all-1.0; full suite + clippy + fmt green on Linux and native Windows.
Diagnostics sweeps: Pixelorama (243 files) 0 error-files; a 2,338-script production project
on a custom engine build: first response ~3.2 s on a fully cold start (previously ~60 s),
0 false positives at every stage — the background dump (1,261 classes, GDExtension classes
included) adopted at ~6.7 s mid-session — and the sweep's error-file set is a strict subset of
the v1.0.1 baseline (3 files fixed, 0 new).

Install

cargo install --git https://github.com/kurushimee/gdls --tag v1.0.2 gd_server

(or omit --tag for the default branch build, as in the README)

or grab a prebuilt binary below — SHA256SUMS covers both archives.


Known issues — fixed in v1.0.3: 19 declared warning codes never emitted (#29); @warning_ignore missed multi-line targets (#28); definition on dotted method calls, cross-file incomingCalls, and prepareCallHierarchy on a call-site callee returned nothing or the wrong target.

v1.0.1 — diagnostics at scale

Choose a tag to compare

@kurushimee kurushimee released this 10 Jun 03:28
ec99b83

The urgent diagnostics-correctness release. A post-v1.0.0 full-project sweep (didOpen every .gd, tally publishDiagnostics) found error-level false positives in ~45–55% of files on real layered projects — all violations of the "never lie" rule, all reproducing on vanilla Godot 4.6.3. v1.0.1 fixes the four families behind that and the long tail the new sweep gate exposed, closes both v1.0.0 follow-ups (#13, #14), and removes the last manual setup step.

Outcome: the Pixelorama sweep reports 0 files with errors (from 133/243 with 1,223 errors); a 2,338-script production project went from 1,051 error-files to 43 — every remaining one independently rejected by Godot itself or using engine-fork-only syntax. Conformance ratchets hold at parser 186/186 and analyzer 300/300. Measured NTFS startup on that project: cold ~10.8 s → 3.5 s, warm ~11.2 s → 2.3 s.

Highlights

  • Cross-file inheritance typing (#15): extends ClassName across files now carries native lineage ($/@onready work) and inherited members (signals, vars, consts, funcs) through a shared, memoized script-chain resolver; self passes compatibility against base classes and native roots.
  • Cross-file member navigation (#13): references find obj.signal.emit(…) sites across files; definition on a member access jumps to the declaration; hover renders var/const member shapes.
  • Zero-config native types (#20): gdls auto-dumps extension_api.json (with project context — GDExtension classes included) into .gdls/ via your Godot binary (godotBinaryPathGDLS_GODOT → PATH), regenerating only when the binary or .gdextension set changes. autoDumpExtensionApi: false opts out.
  • Windows/NTFS startup (#14): the dominant cost was the file watcher's full-tree, handle-per-file arming scan — eliminated (NoCache), with walk-metadata reuse and a discovery-only startup backstop.
  • uid:// autoload script targets resolve (#19); Packed*Array iteration (#17); builtin-constant arithmetic (Vector3.UP * 3.0, #16); cross-file const chains (#18); and a long tail of sweep-found fixes (relative preload paths, autoloads as type annotations, builtin instance members, transform operators, native signals, parameter defaults, X.new() member inference, and more — see the CHANGELOG).

Upgrade note

The on-disk index cache format moved to v2 (interfaces now carry enum values and unnamed-enum hoists) — old caches are ignored automatically; expect one cold start after upgrading.

Full details: CHANGELOG.md.

Install

Download the binary for your platform below, place it on PATH. Native types now configure themselves — see the README quickstart.


Known issues — fixed in v1.0.2: on a machine where no extension_api.json source resolves (fresh install, no Godot on PATH, or the auto-dump fails/times out), v1.0.1 runs with an empty native DB and reports false-positive Could not find type "X" in the current scope. errors for every native class; the synchronous auto-dump can also stall the first request for up to 60 s, and hover on declarations renders an opaque <Script #N> placeholder. Upgrade to v1.0.2.

gdls v1.0.0 — first release

Choose a tag to compare

@kurushimee kurushimee released this 09 Jun 21:23

The first release of gdls — a standalone GDScript language server: a faithful Rust port of
Godot 4.6.3-stable's GDScript frontend (tokenizer → parser → analyzer) speaking LSP over stdio,
with no Godot engine or editor process at runtime. Built for type-aware diagnostics and
navigation at the 3,000–10,000+ .gd file scale.

Highlights

  • Godot-fidelity diagnostics — parser conformance 186/186, analyzer 300/300 against the
    vendored Godot 4.6.3-stable golden corpus; the full warning set (45 active + 3 deprecated-gated)
    with godot / strict / off profiles and per-warning overrides.
  • LSP surface — per-file publishDiagnostics, hover (member/call/preload signatures +
    engine/GDExtension doc prose), definition (incl. class_name-in-expression, preload/load
    res:// strings, autoload names), project-wide references, hierarchical documentSymbol,
    documentLink on res:// literals, implementation (class subtypes + method overrides),
    workspace/symbol, and call hierarchy — the last three exceed Godot's own LSP, which doesn't
    offer them.
  • Autoload-singleton typingGlobal.popup_error(...) resolves like Godot's editor: full
    hover signatures and cross-file references through singleton members.
  • Persistent warm-start cache<project>/.gdls/, keyed on gdls version + native-API content
    hash + project.godot fingerprint with per-file (size, mtime) stat validation; atomic
    last-writer-wins writes make concurrent gdls processes (e.g. Claude Code + an IDE) safe. Warm
    start is >5× faster than a cold scan (14.7× on the 3,000-file synthetic gate); reconcile
    re-parses only stat-changed files.
  • Never crash, never lie — partial ASTs on any input (fuzzed: parse/analyze/index-invariants),
    clamped position conversions, graceful degradation on doc-less GDExtensions, corrupt caches fall
    back to a cold index.

Verification

Final acceptance for this release: the parameterized capability walk
(scripts/m6-acceptance/) passes every row on a real Godot 4.6.3 OSS project (Pixelorama —
committed session), and a Windows-native walk on a 2,338-script production project returns
correct data on every row with the cache stat-diffing 2338 unchanged, 0 reparsed over NTFS.

Install

Download the binary for your platform below (SHA256SUMS included), unpack it onto PATH, or
build from source:

cargo install --path crates/gd_server   # installs `gdls` into ~/.cargo/bin

Generate extension_api.json once per engine rebuild (from inside your project, so installed
GDExtensions are captured), then point initializationOptions.extensionApiPath at it:

godot --dump-extension-api-with-docs

Client wiring (Claude Code plugin manifest, configuration schema): see the
README and docs/05-lsp-cc-integration.md.

Known limitations

  • references/definition don't yet reach signal/var member-access sites through typed bases
    (obj.sig.emit(...) across files — method calls and in-file signal uses work; hover renders
    func/signal member signatures): #13.
  • On Windows/NTFS, startup wall-clock is dominated by the reconcile backstop walk, which masks
    the warm-cache win there (the cache itself validates correctly): #14.
  • Phase 2 (by design): .tscn node typing for $/% (they're deliberately permissive in v1 —
    never a false positive on node access), completion, signatureHelp, rename,
    documentHighlight.

Full details in CHANGELOG.md.


Known issues — fixed in v1.0.1. A post-release full-project diagnostics sweep found error-level false positives in ~45–55% of files on real layered projects (cross-file inheritance typing, builtin-constant folds, packed-array iteration, const chains, and a long tail). Upgrade to v1.0.1, which also makes extension_api.json fully automatic and fixes the Windows/NTFS startup cost.