authoring-godot-prompt…
Use when writing or editing a SKILL.md, a skill's references/*.md, or an agent definition in this repo — required frontmatter,…
Use when calling web APIs or backends from Godot — HTTPRequest, REST/JSON clients, auth headers, downloads, TLS, WebSocketPeer clients, retries, and keeping secrets out of the build
$ npx -y skills add jame581/GodotPrompter --skill web-services --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/web-servicesContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when calling web APIs or backends from Godot — HTTPRequest, REST/JSON clients, auth headers, downloads, TLS, WebSocketPeer clients, retries, and keeping secrets out of the build
name: web-services description: Use when calling web APIs or backends from Godot — HTTPRequest, REST/JSON clients, auth headers, downloads, TLS, WebSocketPeer clients, retries, and keeping secrets out of the build
Talk to REST APIs, leaderboards, analytics, login services, and other HTTP/WebSocket backends. All examples target Godot 4.3+ with no deprecated APIs. GDScript is shown first, then C#.
> **Related skills:** **multiplayer-basics** for real-time game networking with WebSocketMultiplayerPeer, **save-load** for persisting tokens and cached responses, **web-export** for CORS and browser limits, **mobile-development** for Android export permissions, **multithreading** for heavy response parsing off the main thread.
---
| Need | Use | Why | |---|---|---| | Ordinary REST call, file or image download | `HTTPRequest` node | Handles connect, redirects, gzip, timeout; emits one signal when done | | Streaming a response, custom keep-alive, many requests to one host | `HTTPClient` | Low-level; you call `poll()` and drive the state machine yourself | | Persistent two-way channel (chat, live events, lobby service) | `WebSocketPeer` | Client socket; call `poll()` every frame | | Real-time gameplay sync with RPCs | `WebSocketMultiplayerPeer` | Plugs into `MultiplayerAPI` — see **multiplayer-basics** |
**One `HTTPRequest` node runs one request at a time.** A second `request()` while one is in flight returns `ERR_BUSY`. Create one node per concurrent request (Section 3) rather than queueing on a shared node.
---
`request()` only *starts* the request; its return value says whether it could be sent, not whether the server answered. The result arrives on `request_completed(result, response_code, headers, body)`.
func fetch_motd() -> void:
var http := HTTPRequest.new()
http.timeout = 10.0 # Default 0.0 means wait forever.
add_child(http)
var err := http.request("https://api.example.com/v1/motd")
if err != OK:
push_error("Could not start request: %s" % error_string(err))
http.queue_free()
return
var res: Array = await http.request_completed
http.queue_free()
var result: int = res[0]
var code: int = res[1]
var body: PackedByteArray = res[3]
if result != HTTPRequest.RESULT_SUCCESS:
push_warning("Network failure (HTTPRequest.Result %d)" % result)
elif code != 200:
push_warning("Server answered HTTP %d" % code)
else:
print(body.get_string_from_utf8())public async void FetchMotd()
{
var http = new HttpRequest { Timeout = 10.0 }; // Default 0.0 means wait forever.
AddChild(http);
Error err = http.Request("https://api.example.com/v1/motd");
if (err != Error.Ok)
{
GD.PushError($"Could not start request: {err}");
http.QueueFree();
return;
}
Variant[] res = await ToSignal(http, HttpRequest.SignalName.RequestCompleted);
http.QueueFree();
long result = res[0].AsInt64();
long code = res[1].AsInt64();
byte[] body = res[3].AsByteArray();
if (result != (long)HttpRequest.Result.Success)
GD.PushWarning($"Network failure (HttpRequest.Result {result})");
else if (code != 200)
GD.PushWarning($"Server answered HTTP {code}");
else
GD.Print(body.GetStringFromUtf8());
}Check **both** values: `result` is the transport outcome (DNS, TLS, timeout — `RESULT_CANT_RESOLVE`, `RESULT_TLS_HANDSHAKE_ERROR`, `RESULT_TIMEOUT`, …), `response_code` is the HTTP status. A 404 or 500 arrives with `RESULT_SUCCESS`.
---
Wrap the boilerplate once. Register this as an autoload named `Api`; every call spawns its own `HTTPRequest`, so calls can overlap.
# api.gd — autoload "Api"
extends Node
const BASE_URL := "https://api.example.com/v1"
const TIMEOUT_SEC := 10.0
var auth_token: String = ""
## Returns {ok: bool, code: int, data: Variant, error: String}.
func request_json(path: String, method: HTTPClient.Method = HTTPClient.METHOD_GET, payload: Variant = null) -> Dictionary:
var http := HTTPRequest.new()
http.timeout = TIMEOUT_SEC
add_child(http)
var headers := PackedStringArray(["Accept: application/json"])
var body := ""
if payload != null:
headers.append("Content-Type: application/json")
body = JSON.stringify(payload)
if not auth_token.is_empty():
headers.append("Authorization: Bearer " + auth_token)
var err := http.request(BASE_URL + path, headers, method, body)
if err != OK:
http.queue_free()
return {"ok": false, "code": 0, "data": null, "error": "request() failed: " + error_string(err)}
var res: Array = await http.request_completed
http.queue_free()
if res[0] != HTTPRequest.RESULT_SUCCESS:
return {"ok": false, "code": 0, "data": null, "error": "transport error %d" % res[0]}
var code: int = res[1]
var text := (res[3] as PackedByteArray).get_string_from_utf8()
var data: Variant = JSON.parse_string(text) if not text.is_empty() else null
return {"ok": code >= 200 and code < 300, "code": code, "data": data, "error": "" if code < 400 else text}// Api.cs — autoload "Api"
using System.Collections.Generic;
using System.Threading.Tasks;
using Godot;
public partial class Api : Node
{
private const string BaseUrl = "https://api.example.com/v1";
private const double TimeoutSec = 10.0;
public string AuthToken { get; set; } = "";
public readonly record struct ApiResult(bool Ok, long Code, Variant Data, string Error);
public async Task<ApiResult> RequestJson(string path, HttpClient.Method method = HttpClient.Method.Get, Variant payload = default)
{
var http = new HttpRequest { Timeout = TimeoutSec };
AddChild(http);
var headers = new List<string> { "Accept: application/jsAgentic skills framework for Godot 4.x game development. Gives AI coding agents domain-specific expertise for GDScript and C# projects.
Use when writing or editing a SKILL.md, a skill's references/*.md, or an agent definition in this repo — required frontmatter,…
Use when cutting a GodotPrompter release or bumping its version — the version-bump sequence, tag-triggered workflow, and the…
Use when working with 2D-specific systems — TileMaps, parallax scrolling, 2D lights and shadows, canvas layers, particles 2D,…
Use when working with 3D-specific systems — materials, lighting, shadows, environment, global illumination, fog, LOD, occlusion…
Use when building character abilities — Resource-based abilities with cost/cooldown/cast, buffs/debuffs, stat modifiers, gameplay…
Use when creating Godot editor plugins — EditorPlugin, @tool scripts, custom inspectors, and dock panels