Godot Gdscript Patterns
925236118/AlphaAgent
Master Godot 4 GDScript patterns including signals, scenes, state machines, and optimization.
Take screenshots of the Godot editor window or the running game window via the Hastur broker-server remote executor.
$ npx skills add rayxuln/hastur-operation-plugin --skill godot-screenshot -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install rayxuln/hastur-operation-plugin godot-screenshot --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/rayxuln/hastur-operation-plugin.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/godot-screenshot .claude/skills/godot-screenshot && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "godot-screenshot" agent skill from https://github.com/rayxuln/hastur-operation-plugin/tree/main/.claude/skills/godot-screenshot into .claude/skills/godot-screenshot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "godot-screenshot", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/rayxuln/hastur-operation-plugin/tree/main/.claude/skills/godot-screenshotType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add rayxuln/hastur-operation-plugin --skill godot-screenshot -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install rayxuln/hastur-operation-plugin godot-screenshot --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/rayxuln/hastur-operation-plugin.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/godot-screenshot .agents/skills/godot-screenshot && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "godot-screenshot" agent skill from https://github.com/rayxuln/hastur-operation-plugin/tree/main/.claude/skills/godot-screenshot into .agents/skills/godot-screenshot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "godot-screenshot", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add rayxuln/hastur-operation-plugin --skill godot-screenshot -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install rayxuln/hastur-operation-plugin godot-screenshot --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/rayxuln/hastur-operation-plugin.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/godot-screenshot .cursor/skills/godot-screenshot && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "godot-screenshot" agent skill from https://github.com/rayxuln/hastur-operation-plugin/tree/main/.claude/skills/godot-screenshot into .cursor/skills/godot-screenshot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "godot-screenshot", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/rayxuln/hastur-operation-plugin.git --path .claude/skills/godot-screenshot--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add rayxuln/hastur-operation-plugin --skill godot-screenshot -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install rayxuln/hastur-operation-plugin godot-screenshot --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/rayxuln/hastur-operation-plugin.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/godot-screenshot .gemini/skills/godot-screenshot && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "godot-screenshot" agent skill from https://github.com/rayxuln/hastur-operation-plugin/tree/main/.claude/skills/godot-screenshot into .gemini/skills/godot-screenshot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "godot-screenshot", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install rayxuln/hastur-operation-plugin godot-screenshotInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add rayxuln/hastur-operation-plugin --skill godot-screenshot -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/rayxuln/hastur-operation-plugin.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/godot-screenshot .github/skills/godot-screenshot && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "godot-screenshot" agent skill from https://github.com/rayxuln/hastur-operation-plugin/tree/main/.claude/skills/godot-screenshot into .github/skills/godot-screenshot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "godot-screenshot", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add rayxuln/hastur-operation-plugin --skill godot-screenshot -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install rayxuln/hastur-operation-plugin godot-screenshot --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/rayxuln/hastur-operation-plugin.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/godot-screenshot .opencode/skills/godot-screenshot && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "godot-screenshot" agent skill from https://github.com/rayxuln/hastur-operation-plugin/tree/main/.claude/skills/godot-screenshot into .opencode/skills/godot-screenshot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "godot-screenshot", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
godot-screenshotTake screenshots of the Godot editor window or the running game window via the Hastur broker-server remote executor.
Godot Screenshot is an agent skill from rayxuln/hastur-operation-plugin. Take screenshots of the Godot editor window or the running game window via the Hastur broker-server remote executor. Use this skill whenever the user asks to capture, save, or take a screenshot of the Godot editor or game runtime — including phrases like "截图", "screenshot", "capture screen", "save a picture of the editor/game", "snap the viewport", or any request involving saving the visual state of a running Godot instance. Also trigger when the user wants to automate periodic screenshots or compare visual…
Its SKILL.md is about 3.2k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Game Development, covering Game development. It works with Godot. The repository describes itself as: A plugin providing ability for executing any code on Godot Editor. So that any coding agent can do any operations with Godot Editor. This version is for GDScript. It can execute… The licence is MIT.
3 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit eedff7f. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are gdscript).
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Godot Screenshot loads about 3.2k tokens when it runs. Until then it costs about 179 tokens; SKILL.md has 1,092 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from rayxuln/hastur-operation-plugin at commit eedff7f, republished under its MIT licence (© rayxuln). 1,092 words, ~3,220 tokens.
.claude/skills/godot-screenshot/SKILL.md (or your agent's skills folder).This skill captures screenshots from a running Godot editor or game instance and saves them as PNG files. It depends on the godot-remote-executor skill — load it first so you understand how to discover executors, authenticate, and execute GDScript code.
Before using this skill, you must have:
The Godot API for capturing screenshots relies on the viewport's texture. The correct approach is:
var tree = Engine.get_main_loop() as SceneTree
var img = tree.root.get_texture().get_image()This grabs the root Viewport's texture, converts it to an Image, and then you can call img.save_png(path) to write it to disk.
Why tree.root and not get_viewport()? Because in snippet mode your code runs inside a RefCounted instance (not a Node). The get_viewport() convenience method only exists on Node — it is NOT available on RefCounted, EditorInterface, or other non-Node objects. Always use Engine.get_main_loop() to get the SceneTree, then access tree.root to get the root Viewport.
Similarly, EditorInterface does not have a get_viewport() method either. The universal approach that works in all contexts is Engine.get_main_loop().root.
This captures the entire Godot editor window.
Preconditions: An editor executor (type: "editor") must be connected.
var tree = Engine.get_main_loop() as SceneTree
var img = tree.root.get_texture().get_image()
var dict = Time.get_datetime_dict_from_system()
var date_str = "%04d-%02d-%02d" % [dict["year"], dict["month"], dict["day"]]
var time_str = "%02d-%02d-%02d" % [dict["hour"], dict["minute"], dict["second"]]
var rel_path = ".temp/" + date_str + "-" + time_str + "-editor.png"
var abs_path = ProjectSettings.globalize_path("res://" + rel_path)
var dir_abs = ProjectSettings.globalize_path("res://.temp")
if not DirAccess.dir_exists_absolute(dir_abs):
DirAccess.make_dir_recursive_absolute(dir_abs)
var err = img.save_png(abs_path)
executeContext.output("path", rel_path)
executeContext.output("result", "OK" if err == OK else "Error: " + str(err))This captures the running game window.
Preconditions: A game executor (type: "game") must be connected. The game must already be running with the GameExecutor autoload registered.
var tree = Engine.get_main_loop() as SceneTree
var img = tree.root.get_texture().get_image()
var dict = Time.get_datetime_dict_from_system()
var date_str = "%04d-%02d-%02d" % [dict["year"], dict["month"], dict["day"]]
var time_str = "%02d-%02d-%02d" % [dict["hour"], dict["minute"], dict["second"]]
var rel_path = ".temp/" + date_str + "-" + time_str + "-game.png"
var abs_path = ProjectSettings.globalize_path("res://" + rel_path)
var dir_abs = ProjectSettings.globalize_path("res://.temp")
if not DirAccess.dir_exists_absolute(dir_abs):
DirAccess.make_dir_recursive_absolute(dir_abs)
var err = img.save_png(abs_path)
executeContext.output("path", rel_path)
executeContext.output("result", "OK" if err == OK else "Error: " + str(err))If no game executor is available, you may need to launch the game first. See the "Launching the Game" section below.
When the user wants both screenshots, follow this sequence:
GET /api/executors to find connected editor and game executors/api/executors every few seconds until a type: "game" executor appearsIf the game is not running and the user wants it started, execute on the editor executor:
var ei = Engine.get_singleton('EditorInterface')
ei.play_current_scene()
executeContext.output("result", "done")After launching, wait ~5 seconds for the game process to start and the GameExecutor autoload to connect to the broker-server. Poll GET /api/executors until a type: "game" executor appears.
Other launch options:
ei.play_main_scene() — play the project's main sceneei.play_custom_scene("res://path/to/scene.tscn") — play a specific sceneWhen executing code on the game executor, runtime errors will trigger Godot's built-in debugger, which automatically pauses the game process. This causes the executor request to time out (HTTP 504 after 30 seconds) because the game is frozen and cannot complete the execution.
POST /api/execute returns HTTP 504 timeout when targeting the game executorBefore executing any code on the game executor, proactively enable the "Ignore Error Breaks" setting. This prevents the debugger from pausing on script errors. Execute the following on the editor executor:
var tree = Engine.get_main_loop() as SceneTree
var stack_trace_toolbar_path = tree.root.get_node("/root/@EditorNode@18094/@Panel@14/@VBoxContainer@15/DockHSplitMain/@VBoxContainer@28/DockVSplitCenter/@EditorBottomPanel@7422/Debugger/@TabContainer@8422/Session 1/@TabContainer@8425/Stack Trace/@HBoxContainer@8426")
var ignore_btn = stack_trace_toolbar_path.get_node("@Button@8432") as Button
ignore_btn.set_toggle_mode(true)
ignore_btn.set_pressed(true)
ignore_btn.emit_signal("pressed")
executeContext.output("ignore_error_breaks", "enabled")Important caveat about this button:
The "Ignore Error Breaks" button (@Button@8432) is a plain Button with toggle_mode set to false by default. This means:
emit_signal("pressed") does NOT toggle its visual/functional stateset_pressed(true) is silently ignored because toggle_mode is falseset_pressed_no_signal(true) is also silently ignoredThe only reliable way to activate it programmatically is:
set_toggle_mode(true) to enable toggle behaviorset_pressed(true) to set the pressed stateemit_signal("pressed") to trigger the internal handlerWithout step 1, steps 2 and 3 have no effect on the button state.
Note on node paths: The hardcoded node paths in the debugger toolbar (e.g., @EditorBottomPanel@7422, @TabContainer@8422) contain auto-generated numeric suffixes that may change between Godot sessions or versions. If the path stops working, you need to re-discover the debugger nodes by walking the editor's scene tree. The general path structure is:
/root/@EditorNode@.../@Panel@.../@VBoxContainer@.../DockHSplitMain/@VBoxContainer@.../DockVSplitCenter/@EditorBottomPanel@.../Debugger/@TabContainer@.../Session 1/@TabContainer@.../Stack Trace/@HBoxContainer@...To re-discover the path, search for the "Stack Trace" tab and its toolbar by walking the tree looking for nodes named "Stack Trace" or buttons with tooltip "Ignore Error Breaks":
var tree = Engine.get_main_loop() as SceneTree
var ei = Engine.get_singleton('EditorInterface')
var base = ei.get_base_control()
var stack = [[base, 0]]
var results = []
while stack.size() > 0:
var pair = stack.pop_back()
var node = pair[0]
var depth = pair[1]
if depth > 25:
continue
if node.name.find("Stack Trace") != -1:
results.append(str(node.get_path()) + " (" + node.get_class() + ")")
for child in node.get_children():
stack.append([child, depth + 1])
for r in results:
executeContext.output("stack_trace_node", r)Then look for the @HBoxContainer child of the "Stack Trace" node — that's the toolbar. Enumerate its children to find buttons and their tooltips:
var toolbar = tree.root.get_node("<path to Stack Trace's HBoxContainer>")
for child in toolbar.get_children():
if child is BaseButton:
executeContext.output("button", child.name + " tooltip=" + child.tooltip_text)Match by tooltip text: "Ignore Error Breaks" for the ignore button, "Continue" for the continue button.
If the game is already paused by the debugger, you need to:
The "Continue" button is in the same toolbar. After discovering the toolbar path (see above), find the button with tooltip "Continue" and activate it:
var toolbar = tree.root.get_node("<path to Stack Trace's HBoxContainer>")
var continue_btn = toolbar.get_node("@Button@...") # the one with tooltip "Continue"
continue_btn.emit_signal("pressed")The Continue button is a normal (non-toggle) button, so emit_signal("pressed") works correctly.
Always ensure the target directory exists before saving. The .temp/ directory may not exist in the project:
var dir_abs = ProjectSettings.globalize_path("res://.temp")
if not DirAccess.dir_exists_absolute(dir_abs):
DirAccess.make_dir_recursive_absolute(dir_abs)Use ProjectSettings.globalize_path("res://...") to convert a res:// path to an absolute filesystem path that Image.save_png() can write to. GDScript's Image.save_png() requires an absolute path.
Use the pattern <date>-<time>-<target>.png for filenames:
YYYY-MM-DDHH-MM-SSeditor or gameExample: .temp/2026-04-10-21-45-11-editor.png
Use Time.get_datetime_dict_from_system() to get the current date and time:
var dict = Time.get_datetime_dict_from_system()
var date_str = "%04d-%02d-%02d" % [dict["year"], dict["month"], dict["day"]]
var time_str = "%02d-%02d-%02d" % [dict["hour"], dict["minute"], dict["second"]]Image.save_png() returns an Error enum. Always check it:
var err = img.save_png(abs_path)
executeContext.output("result", "OK" if err == OK else "Error: " + str(err))Error code 7 (ERR_FILE_NOT_FOUND) typically means the directory doesn't exist. Error code 9 (ERR_FILE_BAD_PATH) means the path is malformed. See the Error enum table in the godot-remote-executor skill for the full list.
| Pitfall | Cause | Solution |
|---|---|---|
get_viewport() not found | Snippet mode runs in RefCounted, not Node | Use Engine.get_main_loop().root |
EditorInterface.get_viewport() not found | EditorInterface has no get_viewport() method | Use Engine.get_main_loop().root |
| Game screenshot request times out (504) | Debugger auto-paused the game on a runtime error | Enable "Ignore Error Breaks" before executing game code |
| "Ignore Error Breaks" button won't activate | Button has toggle_mode=false, set_pressed is ignored | Call set_toggle_mode(true) first, then set_pressed(true), then emit_signal("pressed") |
| Game not paused but executor not responding | Game might be in a tight loop or crashed | Stop and restart the game via editor |
save_png returns error 7 | Target directory doesn't exist | Create directory with DirAccess.make_dir_recursive_absolute() |
| Node paths stop working | Auto-generated node names change between sessions | Re-discover by walking the scene tree and matching by name/tooltip |
© rayxuln, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .claude/skills/godot-screenshot of rayxuln/hastur-operation-plugin.
Open the folder on GitHubat commit eedff7f
Godot Screenshot next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Godot Screenshot this skillrayxuln/hastur-operation-plugin | 241 | — | ~3.2k | Automated safety check: Pass | MIT | |
| Godot Gdscript Patterns925236118/AlphaAgent | 103 | 10 repos | ~5k | Automated safety check: Pass | MIT | |
| 2D Map and Scene Generator0x0funky/agent-sprite-forge | 4.4k | — | ~2.9k | Automated safety check: Pass | MIT | |
| Godot UI Integrationzimo-xiao-zheng/godot-ui-integration | 285 | — | ~1.5k | Automated safety check: Pass | MIT | |
| Godot Wechat Minigame Adaptergodothub/godot-minigame | 187 | — | ~1.5k | Automated safety check: Pass | MIT | |
| AI Game Art Pipelineybuild-ai/ai-game-art-pipeline-skill | 297 | — | ~1.1k | Automated safety check: Pass | MIT |
925236118/AlphaAgent
Master Godot 4 GDScript patterns including signals, scenes, state machines, and optimization.
0x0funky/agent-sprite-forge
Plans and builds 2D game maps and scenes, from tilemaps and parallax backgrounds to HD-2D plates, with collision checks, a playable HTML preview and Tiled, Godot or LDtk export.
zimo-xiao-zheng/godot-ui-integration
Build or revise Godot UI from an approved design, separated art, or a visual reference when scene structure, gameplay binding, and runtime visual verification all matter.
godothub/godot-minigame
Apply the bundled self-contained Godot WeChat Mini Game adapter kit to an official Godot checkout.
ybuild-ai/ai-game-art-pipeline-skill
Provider-neutral open-source skill for planning and producing game-runtime art assets and animation: static props/icons, canonical character sheets, combat sprites, 3D/video motion references…
RandallLiuXin/GodotMaker
Runtime debugging and live project inspection via godot-mcp.
Works with
Categories
Take screenshots of the Godot editor window or the running game window via the Hastur broker-server remote executor. Godot Screenshot is an agent skill from rayxuln/hastur-operation-plugin. Take screenshots of the Godot editor window or the running game window via the Hastur broker-server remote executor.
Godot Screenshot fits situations like: the user asks to capture; take a screenshot of the Godot editor; game runtime — including phrases like 截图; save a picture of the editor/game.
Run `npx skills add rayxuln/hastur-operation-plugin --skill godot-screenshot -a claude-code`. Or copy the skill folder (.claude/skills/godot-screenshot in rayxuln/hastur-operation-plugin) into .claude/skills/godot-screenshot in your project. Claude Code loads it when a task matches its description.
Run `npx skills add rayxuln/hastur-operation-plugin --skill godot-screenshot -a codex`. Or copy the skill folder (.claude/skills/godot-screenshot in rayxuln/hastur-operation-plugin) into .agents/skills/godot-screenshot in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add rayxuln/hastur-operation-plugin --skill godot-screenshot -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/godot-screenshot, .gemini/skills/godot-screenshot, .github/skills/godot-screenshot and .opencode/skills/godot-screenshot in your project.
SKILL.md names no scripts, command-line tools or credentials: Godot Screenshot is instructions for the agent only.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Godot Screenshot is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.2k tokens (SKILL.md is roughly 13k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Godot Screenshot: Godot Gdscript Patterns (925236118/AlphaAgent, 103 stars), 2D Map and Scene Generator (0x0funky/agent-sprite-forge, 4.4k stars), Godot UI Integration (zimo-xiao-zheng/godot-ui-integration, 285 stars) and Godot Wechat Minigame Adapter (godothub/godot-minigame, 187 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
rayxuln (a GitHub user) maintains it in rayxuln/hastur-operation-plugin, which has 241 GitHub stars. The repository was last updated on April 11, 2026.
Source: rayxuln/hastur-operation-plugin on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.